[
  {
    "path": ".gitignore",
    "content": "# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n*.tlog\nVS2015/SG14/SG14_test/Release/vc140.pdb\n*.obj\nVS2015/SG14/SG14_test/Release/SG14_test.log\n*.pdb\nVS2015/SG14/SG14_test/Debug/vc120.idb\n*.idb\n*.ipdb\nVS2015/SG14/Release/SG14_test.iobj\n*.ilk\nVS2015/SG14/Release/SG14_test.exe\n*.exe\nVS2015/SG14/.vs/SG14/v14/.suo\n*.opensdf\nVS2015/SG14/SG14.sdf\n*.suo\nVS2015/SG14/SG14.sdf\nVS2015/SG14/SG14_test/Debug/SG14_test.log\n\n# Xcode\nxcuserdata\n\n# CLion\ncmake/.idea\n/.vs\n/.vs/SG14/v15\n/.vs/slnx.sqlite\n/.vs/SG14/v15/Browse.VC.opendb\n/.vs/SG14/v15/Browse.VC.db\n/.vs/ProjectSettings.json\n/build/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: cpp\n\nbefore_install:\n  - if [[ \"$TRAVIS_OS_NAME\" == \"osx\" ]]; then\n      brew update;\n      brew upgrade cmake;\n      brew install cmake;\n    fi\n  - if [[ \"$TRAVIS_OS_NAME\" == \"linux\" ]]; then\n      eval \"${MATRIX_EVAL}\";\n      DEPS_DIR=\"${TRAVIS_BUILD_DIR}/deps\";\n      mkdir ${DEPS_DIR} && cd ${DEPS_DIR};\n      CMAKE_URL=\"https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.tar.gz\";\n      mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake;\n      export PATH=${DEPS_DIR}/cmake/bin:${PATH};\n      cd ..;\n    fi\n\nmatrix:\n  include:\n    - os: windows\n      env:\n        - CONFIG=Release\n\n    - os: windows\n      env:\n        - CONFIG=Debug\n\n    - os: osx\n      osx_image: xcode9.2\n      env:\n        - CONFIG=Release\n\n    - os: osx\n      osx_image: xcode9.2\n      env:\n        - CONFIG=Debug\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-5\n            - g++-5\n      env:\n        - MATRIX_EVAL=\"CC=gcc-5 && CXX=g++-5 && CONFIG=Debug\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-5\n            - g++-5\n      env:\n        - MATRIX_EVAL=\"CC=gcc-5 && CXX=g++-5 && CONFIG=Release\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-6\n            - g++-6\n      env:\n        - MATRIX_EVAL=\"CC=gcc-6 && CXX=g++-6 && CONFIG=Debug\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-6\n            - g++-6\n      env:\n        - MATRIX_EVAL=\"CC=gcc-6 && CXX=g++-6 && CONFIG=Release\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-7\n            - g++-7\n      env:\n        - MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7 && CONFIG=Debug\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-7\n            - g++-7\n      env:\n        - MATRIX_EVAL=\"CC=gcc-7 && CXX=g++-7 && CONFIG=Release\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-8\n            - g++-8\n      env:\n        - MATRIX_EVAL=\"CC=gcc-8 && CXX=g++-8 && CONFIG=Debug\"\n\n    - os: linux\n      dist: trusty\n      addons:\n        apt:\n          sources:\n            - ubuntu-toolchain-r-test\n          packages:\n            - gcc-8\n            - g++-8\n      env:\n        - MATRIX_EVAL=\"CC=gcc-8 && CXX=g++-8 && CONFIG=Release\"\n\nscript:\n  - mkdir build && cd build && cmake .. && cmake --build . && ./bin/sg14_tests\n\nnotifications:\n  email:\n    on_success: never\n    on_failure: always\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.10)\nproject(sg14 CXX)\n\nfind_package(Threads REQUIRED)\n\n# Prefer C++17, downgrade if it isn't available.\nset(CMAKE_CXX_STANDARD_REQUIRED OFF)\nset(CMAKE_CXX_STANDARD 17)\n\nset(SG14_INCLUDE_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/SG14\")\nset(SG14_TEST_SOURCE_DIRECTORY \"${CMAKE_CURRENT_SOURCE_DIR}/SG14_test\")\n\n# Output binary to predictable location.\nset(BINARY_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})\nset(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})\nset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BINARY_OUT_DIR})\n\nforeach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})\n\tstring(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)\n\tset(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})\n\tset(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})\n\tset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUT_DIR})\nendforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES)\n\nlink_directories(${CMAKE_CURRENT_BINARY_DIR}/lib) # For future use with testing library.\n\n##\n# Project\n##\nadd_library(${PROJECT_NAME} INTERFACE)\n\ninclude(GNUInstallDirs)\n\ntarget_include_directories(${PROJECT_NAME} INTERFACE\n\t$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>\n\t$<BUILD_INTERFACE:${SG14_INCLUDE_DIRECTORY}>\n)\n\n##\n# Unit Tests\n##\nset(TEST_SOURCE_FILES\n    ${SG14_TEST_SOURCE_DIRECTORY}/main.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/flat_map_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/flat_set_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/inplace_function_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/plf_colony_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/ring_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/slot_map_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/uninitialized_test.cpp\n    ${SG14_TEST_SOURCE_DIRECTORY}/unstable_remove_test.cpp\n)\n\nset(TEST_NAME ${PROJECT_NAME}_tests)\nadd_executable(${TEST_NAME} ${TEST_SOURCE_FILES})\ntarget_link_libraries(${TEST_NAME} ${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})\ntarget_include_directories(${TEST_NAME} PRIVATE \"${SG14_TEST_SOURCE_DIRECTORY}\")\n\n# Compile options\nif (\"${CMAKE_CXX_COMPILER_ID}\" MATCHES \"Clang\")\n\ttarget_compile_options(${TEST_NAME} PRIVATE -Wall -Wextra -Werror)\nelseif (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"GNU\")\n\ttarget_compile_options(${TEST_NAME} PRIVATE -Wall -Wextra -Werror)\n\tset_source_files_properties(${SG14_TEST_SOURCE_DIRECTORY}/plf_colony_test.cpp PROPERTIES\n\t\tCOMPILE_FLAGS \"-Wno-unused-parameter\"\n\t)\n\tif (CMAKE_CXX_COMPILER_VERSION MATCHES \"^7.*\")\n\t\tset_source_files_properties(${SG14_TEST_SOURCE_DIRECTORY}/slot_map_test.cpp PROPERTIES\n\t\t\tCOMPILE_FLAGS \"-Wno-error=unused-variable -Wno-error=unused-but-set-variable\") # Fix gcc7 issues with structured bindings\n\t\tmessage(\"Disabled -Wunused-variable and -Wunused-but-set-variable for gcc ${CMAKE_CXX_COMPILER_VERSION}.\")\n\tendif()\nelseif (\"${CMAKE_CXX_COMPILER_ID}\" STREQUAL \"MSVC\")\n\tset_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${TEST_NAME})\n\ttarget_compile_options(${TEST_NAME} PRIVATE /Zc:__cplusplus /permissive- /W4 /WX)\n\tadd_definitions(-DNOMINMAX -D_SCL_SECURE_NO_WARNINGS)\n\tset_source_files_properties(${SG14_TEST_SOURCE_DIRECTORY}/plf_colony_test.cpp PROPERTIES\n\t\tCOMPILE_FLAGS \"/wd4127\") # Disable conditional expression is constant, use if constexpr\nendif()\n\ninstall(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}_targets)\n\ninstall(EXPORT ${PROJECT_NAME}_targets\n    NAMESPACE ${PROJECT_NAME}::\n    FILE ${PROJECT_NAME}-config.cmake\n    DESTINATION \"${CMAKE_INSTALL_DATADIR}/cmake/${PROJECT_NAME}\"\n)\n\ninstall(DIRECTORY \"${SG14_INCLUDE_DIRECTORY}\" DESTINATION \"${CMAKE_INSTALL_INCLUDEDIR}\")\n\n"
  },
  {
    "path": "Docs/Proposals/D0447R16 - Introduction of hive to the Standard Library.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n<html>\r\n<head>\r\n  <meta name=\"viewport\"\r\n  content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0\">\r\n  <meta name=\"viewport\" content=\"width=device-width\">\r\n  <meta content=\"True\" name=\"HandheldFriendly\">\r\n  <meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\r\n  <title>Introduction of std::hive to the standard library</title>\r\n  <style type=\"text/css\">\r\n    \tpre {\r\n        overflow-x: auto;\r\n        white-space: pre-wrap;\r\n        word-wrap: break-word;\r\n      }\r\n      body {\r\n         font-size: 12pt;\r\n         font-weight: normal;\r\n         font-style: normal;\r\n                        font-family: serif;\r\n         color: black;\r\n         background-color: white;\r\n         line-height: 1.2em;\r\n         margin-left: 4em;\r\n         margin-right: 2em;\r\n      }\r\n      /* paragraphs */\r\n\r\n      p {\r\n         padding: 0;\r\n         line-height: 1.3em;\r\n         margin-top: 1.2em;\r\n         margin-bottom: 1em;\r\n         text-align: left;\r\n      }\r\n\r\n      table  {\r\n         margin-top: 3.8em;\r\n         margin-bottom: 2em;\r\n         text-align: left;\r\n         table-layout:fixed;\r\n         width:100%;\r\n      }\r\n      td {\r\n      \toverflow:auto;\r\n        word-wrap:break-word;\r\n      }\r\n\r\n      /* headings */\r\n\r\n      h1 {\r\n         font-size: 195%;\r\n         font-weight: bold;\r\n         font-style: normal;\r\n         font-variant: small-caps;\r\n         line-height: 1.6em;\r\n         text-align: left;\r\n         padding: 0;\r\n         margin-top: 3.5em;\r\n         margin-bottom: 1.7em;\r\n      }\r\n      h2 {\r\n         font-size: 122%;\r\n         font-weight: bold;\r\n         font-style: normal;\r\n         text-decoration: underline;\r\n         padding: 0;\r\n         margin-top: 4.5em;\r\n         margin-bottom: 1.1em;\r\n      }\r\n      h3 {\r\n         font-size: 110%;\r\n         font-weight: bold;\r\n         font-style: normal;\r\n         text-decoration: underline;\r\n         padding: 0;\r\n         margin-top: 4em;\r\n         margin-bottom: 1.1em;\r\n      }\r\n      h4 {\r\n         font-size: 100%;\r\n         font-weight: bold;\r\n         font-style: normal;\r\n         padding: 0;\r\n         margin-top: 4em;\r\n         margin-bottom: 1.1em;\r\n      }\r\n      h5 {\r\n         font-size: 90%;\r\n         font-weight: bold;\r\n         font-style: italic;\r\n         padding: 0;\r\n         margin-top: 3em;\r\n         margin-bottom: 1em;\r\n      }\r\n      h6 {\r\n         font-size: 80%;\r\n         font-weight: bold;\r\n         font-style: normal;\r\n         padding: 0;\r\n         margin-top: 1em;\r\n         margin-bottom: 1em;\r\n      }\r\n      /* divisions */\r\n\r\n      div {\r\n         padding: 0;\r\n         margin-top: 0em;\r\n         margin-bottom: 0em;\r\n      }\r\n      ul {\r\n         margin: 12pt 0pt 22pt 18pt;\r\n         padding: 0pt 0pt 0pt 0pt;\r\n         list-style-type: square;\r\n         font-size: 98%;\r\n      }\r\n      ol {\r\n         margin: 12pt 0pt 22pt 17pt;\r\n         padding: 0pt 0pt 0pt 0pt;\r\n      }\r\n      li {\r\n         margin: 0pt 0pt 10.5pt 0pt;\r\n         padding: 0pt 0pt 0pt 0pt;\r\n         text-indent: 0pt;\r\n         display: list-item;\r\n      }\r\n      /* inline */\r\n\r\n      strong {\r\n         font-weight: bold;\r\n      }\r\n      sup,\r\n      sub {\r\n         vertical-align: baseline;\r\n         position: relative;\r\n         top: -0.4em;\r\n         font-size: 70%;\r\n      }\r\n      sub {\r\n         top: 0.4em;\r\n      }\r\n      em {\r\n         font-style: italic;\r\n      }\r\n                code {\r\n                    font-family: Courier New, Courier, monospace;\r\n                    font-size: 90%;\r\n                    padding: 0;\r\n                    word-wrap:break-word;\r\n                   }\r\n      ins {\r\n         background-color: yellow;\r\n         text-decoration: underline;\r\n      }\r\n      del {\r\n         text-decoration: line-through;\r\n      }\r\n      a:hover {\r\n         color: #4398E1;\r\n      }\r\n      a:active {\r\n         color: #4598E1;\r\n         text-decoration: none;\r\n      }\r\n      a:link.review {\r\n         color: #AAAAAF;\r\n      }\r\n      a:hover.review {\r\n         color: #4398E1;\r\n      }\r\n      a:visited.review {\r\n         color: #444444;\r\n      }\r\n      a:active.review {\r\n         color: #AAAAAF;\r\n         text-decoration: none;\r\n      }\r\n  </style>\r\n</head>\r\n\r\n<body>\r\nAudience: LEWG, SG14, WG21<br>\r\nDocument number: D0447R16<br>\r\nDate: 2021-06-21<br>\r\nProject: Introduction of std::hive to the standard library<br>\r\nReply-to: Matthew Bentley &lt;mattreecebentley@gmail.com&gt;<br>\r\n\r\n\r\n<h1>Introduction of std::hive to the standard library</h1>\r\n\r\n<h2>Table of Contents</h2>\r\n<ol type=\"I\">\r\n  <li><a href=\"#introduction\">Introduction</a></li>\r\n  <li><a href=\"#questions\">Questions for the committee</a></li>\r\n  <li><a href=\"#motivation\">Motivation and Scope</a></li>\r\n  <li><a href=\"#impact\">Impact On the Standard</a></li>\r\n  <li><a href=\"#design\">Design Decisions</a></li>\r\n  <li><a href=\"#technical\">Technical Specification</a></li>\r\n  <li><a href=\"#acknowledgements\">Acknowledgements</a></li>\r\n  <li>Appendixes:\r\n    <ol type=\"A\">\r\n      <li><a href=\"#basicusage\">Basic usage examples</a></li>\r\n      <li><a href=\"#benchmarks\">Reference implementation benchmarks</a></li>\r\n      <li><a href=\"#faq\">Frequently Asked Questions</a></li>\r\n      <li><a href=\"#responses\">Specific responses to previous committee feedback</a></li>\r\n      <li><a href=\"#sg14gameengine\">Typical game engine requirements</a></li>\r\n      <li><a href=\"#timecomplexityexplanations\">Time complexity requirement explanations</a></li>\r\n\t\t<li><a href=\"#yunoconstexpr\">Why not constexpr?</a></li>\r\n\t\t<li><a href=\"#referencediff\">Reference implementation differences and link</a></li>\r\n    </ol>\r\n  </li>\r\n</ol>\r\n\r\n<h2><a id=\"revisions\"></a>Revision history</h2>\r\n<ul>\r\n  <li>R16: Range-constructor corrected to allow sentinels.</li>\r\n  <li>R15: Added throw details to splice. Further design decisions information on reshape and splice. Assign() overload for sentinels (differing iterator types) added. Minor text snaffu corrections. Colony changed to hive based on D2332R0.</li>\r\n  <li>R14: get_iterator_from_pointer changed to get_iterator - the pointer part is implied by the fact that it's the only argument. Added const_iterator overload for get_iterator - which takes a const_pointer and is a const function. Some wording corrections, additional design decisions information. HTML corrections.</li>\r\n  <li>R13: Revisions based on committee feedback. Skipfield template parameter changed to priority enum in order to not over-specify container implementation. Other wording changes to reduce over-specifying implementation. Some non-member template functions moved to be friend functions. std::limits changed to std::hive_limits. block_limits() changed to block_capacity_limits().</li>\r\n  <li>R12: Fill, range and initializer_list inserts changed to void return, since the insertions are not guaranteed to be sequential in terms of hive order and therefore returning an iterator to the first insertion is not useful. Non-default-value fill constructor changed to non-explicit to match other std:: containers. Correction to reserve() wording. Other minor corrections and clarity improvements.</li>\r\n  <li>R11: Overhaul of technical specification to be more 'wording-like'. Minor\r\n    alterations &amp; clarifications. Additional alternative approach added to\r\n    Design Decisions under skipfield information. Overall rewording. Reordering\r\n    based on feedback. Removal of some easily-replicated 'helper' functions.\r\n    Change to noexcept guarantees. Assign added. get_block_capacity_limits and\r\n    set_block_capacity_limits functions renamed to block_limits and reshape.\r\n    Addition of block-limits default constructors. Reserve() and\r\n    shrink_to_fit() reintroduced. Trim(), erase and erase_if overloads added.</li>\r\n  <li>R10: Additional information about time complexity requirements added to\r\n    appendix, some minor corrections to time complexity info. The 'bentley\r\n    pattern' (this was always a temporary name) is renamed to the more astute\r\n    'low-complexity jump-counting pattern'. Likewise the 'advanced\r\n    jump-counting skipfield' is renamed to the 'high-complexity jump-counting\r\n    pattern' - for reasoning behind this go <a href=\"https://plflib.org/blog.htm#whatsinaname\">here</a>. Both refer to\r\n    time complexity of operations, as opposed to algorithmic complexity. Some\r\n    other corrections.</li>\r\n  <li>R9: Link to Bentley pattern paper added, and is spellchecked now.</li>\r\n  <li>R8: Correction to SIMD info. Correction to structure (missing appendices\r\n    title, member functions and technical specification were conjoined,\r\n    acknowledgments section had mysteriously gone missing since an earlier\r\n    version, now restored and updated). Update intro. HTML corrections.</li>\r\n  <li>R7: Minor changes to member functions.</li>\r\n  <li>R6: Re-write. Reserve() and shrink_to_fit() removed from\r\n  specification.</li>\r\n  <li>R5: Additional note for reserve, re-write of introduction.</li>\r\n  <li>R4: Addition of revision history and review feedback appendices. General\r\n    rewording. Cutting of some dead wood. Addition of some more dead wood.\r\n    Reversion to HTML, benchmarks moved to external URL, based on feedback.\r\n    Change of font to Times New Roman based on looking at what other papers\r\n    were using, though I did briefly consider Comic Sans. Change to insert\r\n    specifications.</li>\r\n  <li>R3: Jonathan Wakely's extensive technical critique has been actioned on,\r\n    in both documentation and the reference implementation. \"Be clearer about\r\n    what operations this supports, early in the paper.\" - done (V. Technical\r\n    Specifications). \"Be clear about the O() time of each operation, early in\r\n    the paper.\" - done for main operations, see V. Technical Specifications.\r\n    Responses to some other feedbacks included in the foreword.</li>\r\n  <li>R2: Rewording.</li>\r\n</ul>\r\n\r\n<h2><a id=\"introduction\"></a>I. Introduction</h2>\r\n\r\n<p>The purpose of a container in the standard library cannot be to provide the\r\noptimal solution for all scenarios. Inevitably in fields such as\r\nhigh-performance trading or gaming, the optimal solution within critical loops\r\nwill be a custom-made one that fits that scenario perfectly. However, outside\r\nof the most critical of hot paths, there is a wide range of application for\r\nmore generalized solutions.</p>\r\n\r\n<p>hive is a formalisation, extension and optimization of what is typically\r\nknown as a 'bucket array' container in game programming circles; similar\r\nstructures exist in various incarnations across the high-performance computing,\r\nhigh performance trading, 3D simulation, physics simulation, robotics, server/client\r\napplication and particle simulation fields (see: <a href=\"https://groups.google.com/a/isocpp.org/forum/#!topic/sg14/1iWHyVnsLBQ\">https://groups.google.com/a/isocpp.org/forum/#!topic/sg14/1iWHyVnsLBQ</a>).</p>\r\n\r\n<p>The concept of a bucket array is: you have multiple memory blocks of\r\nelements, and a boolean token for each element which denotes whether or not\r\nthat element is 'active' or 'erased', commonly known as a skipfield. If it is\r\n'erased', it is skipped over during iteration. When all elements in a block are\r\nerased, the block is removed, so that iteration does not lose performance by\r\nhaving to skip empty blocks. If an insertion occurs when all the blocks are\r\nfull, a new memory block is allocated.</p>\r\n\r\n<p>The advantages of this structure are as follows: because a skipfield is\r\nused, no reallocation of elements is necessary upon erasure. Because the\r\nstructure uses multiple memory blocks, insertions to a full container also do\r\nnot trigger reallocations. This means that element memory locations stay stable\r\nand iterators stay valid regardless of erasure/insertion. This is highly\r\ndesirable, for example, <a href=\"#sg14gameengine\">in game programming</a>\r\nbecause there are usually multiple elements in different containers which need\r\nto reference each other during gameplay and elements are being inserted or\r\nerased in real time.</p>\r\n\r\n<p>Problematic aspects of a typical bucket array are that they tend to have a\r\nfixed memory block size, do not re-use memory locations from erased elements,\r\nand utilize a boolean skipfield. The fixed block size (as opposed to block\r\nsizes with a growth factor) and lack of erased-element re-use leads to far more\r\nallocations/deallocations than is necessary. Given that allocation is a costly\r\noperation in most operating systems, this becomes important in\r\nperformance-critical environments. The boolean skipfield makes iteration time\r\ncomplexity undefined, as there is no way of knowing ahead of time how many\r\nerased elements occur between any two non-erased elements. This can create\r\nvariable latency during iteration. It also requires branching code, which may\r\ncause issues on processors with deep pipelines and poor branch-prediction\r\nfailure performance.</p>\r\n\r\n<p>A hive uses a non-boolean method for skipping erased elements, which allows for O(1) amortized iteration time complexity\r\nand more-predictable iteration performance than a bucket array. It also\r\nutilizes a growth factor for memory blocks and reuses erased element locations\r\nupon insertion, which leads to fewer allocations/reallocations. Because it\r\nreuses erased element memory space, the exact location of insertion is\r\nundefined, unless no erasures have occurred or an equal number of erasures and\r\ninsertions have occurred (in which case the insertion location is the back of\r\nthe container). The container is therefore considered unordered but sortable.\r\nLastly, because there is no way of predicting in advance where erasures\r\n('skips') may occur during iteration, an O(1) time complexity [ ] operator is\r\nnot necessarily possible (depending on implementation) and therefore, the container is bidirectional but not random-access.</p>\r\n\r\n<p>There are two patterns for accessing stored elements in a hive: the first\r\nis to iterate over the container and process each element (or skip some\r\nelements using the advance/prev/next/iterator ++/-- functions). The second is\r\nto store the iterator returned by the insert() function (or a pointer derived\r\nfrom the iterator) in some other structure and access the inserted element in\r\nthat way. To better understand how insertion and erasure work in a hive, see\r\nthe following images.</p>\r\n\r\n<h3>Insertion to back</h3>\r\n\r\n<p>The following images demonstrate how insertion works in a hive compared to\r\na vector when size == capacity.</p>\r\n<img src=\"https://plflib.org/vector_addition.gif\" alt=\"Visual demonstration of inserting to a full vector\"\r\nstyle=\"max-width: 100%; height: auto;\">\r\n<img src=\"https://plflib.org/hive_addition.gif\"\r\nalt=\"Visual demonstration of inserting to a full hive\"\r\nstyle=\"max-width: 100%; height: auto;\">\r\n\r\n<h3>Non-back erasure</h3>\r\n\r\n<p>The following images demonstrate how non-back erasure works in a hive\r\ncompared to a vector.</p>\r\n<img src=\"https://plflib.org/vector_erasure.gif\"\r\nalt=\"Visual demonstration of randomly erasing from a vector\"\r\nstyle=\"max-width: 100%; height: auto;\">\r\n<img src=\"https://plflib.org/hive_erasure.gif\"\r\nalt=\"Visual demonstration of randomly erasing from a hive\"\r\nstyle=\"max-width: 100%; height: auto;\">\r\n\r\n<h2><a id=\"questions\"></a>II. Questions for the Committee</h2>\r\n<ol>\r\n\t<li>It is possible to make the memory() function constant time at a cost (see details in it's entry in the design decisions section of the paper) but since this is expected to be a seldom-used function I've decided not to do so and leave the time complexity as implementation-defined. If there are any objections, please state them. Also, memory_usage() has been suggested as a better name?</li>\r\n\t<li>The conditions under which memory blocks are retained by the erase() functions and added to the \"reserved\" pile instead of deallocated, is presently implementation-defined. Are there any objections to this? Should we define this? See the notes on erase() in Design Decisions, and the item in the FAQ. One option is to specify that only the current back block may be retained, however I feel like this should be implementation-defined.</li>\r\n\t<li>Given that this is a largely unordered container, should resize() be included? Currently it is not and I see no particular reason to do so, but if there are valid reasons let me know.</li>\r\n\t<li>Bikeshedding is welcome for reshape(). Was previously set_block_capacity_limits(), which is more clear, but does not describe the action when container already contains blocks which are outside of the newly-specified capacity limits. change_block_capacity_limits()?</li>\r\n</ol>\r\n\r\n<h2><a id=\"motivation\"></a>III. Motivation and Scope</h2>\r\n\r\n<p><i>Note: Throughout this document I will use the term 'link' to denote any\r\nform of referencing between elements whether it be via\r\nids/iterators/pointers/indexes/references/etc.</i></p>\r\n\r\n<p>There are situations where data is heavily interlinked, iterated over\r\nfrequently, and changing often. An example is the typical video game engine.\r\nMost games will have a central generic 'entity' or 'actor' class, regardless of\r\ntheir overall schema (an entity class does not imply an <a\r\nhref=\"https://en.wikipedia.org/wiki/Entity-component-system\">ECS</a>).\r\nEntity/actor objects tend to be 'has a'-style objects rather than 'is a'-style\r\nobjects, which link to, rather than contain, shared resources like sprites,\r\nsounds and so on. Those shared resources are usually located in separate\r\ncontainers/arrays so that they can re-used by multiple entities. Entities are\r\nin turn referenced by other structures within a game engine, such as\r\nquadtrees/octrees, level structures, and so on.</p>\r\n\r\n<p>Entities may be erased at any time (for example, a wall gets destroyed and\r\nno longer is required to be processed by the game's engine, so is erased) and\r\nnew entities inserted (for example, a new enemy is spawned). While this is all\r\nhappening the links between entities, resources and superstructures such as\r\nlevels and quadtrees, must stay valid in order for the game to run. The order\r\nof the entities and resources themselves within the containers is, in the\r\ncontext of a game, typically unimportant, so an unordered container is okay.</p>\r\n\r\n<p>Unfortunately the container with the best iteration performance in the\r\nstandard library, vector<sup><a href=\"#benchmarks\">[1]</a></sup>, loses pointer\r\nvalidity to elements within it upon insertion, and pointer/index validity upon\r\nerasure. This tends to lead to sophisticated and often restrictive workarounds\r\nwhen developers attempt to utilize vector or similar containers under the above\r\ncircumstances.</p>\r\n\r\n<p>std::list and the like are not suitable due to their poor locality, which\r\nleads to poor cache performance during iteration. This is however an ideal\r\nsituation for a container such as hive, which has a high degree of locality.\r\nEven though that locality can be punctuated by gaps from erased elements, it\r\nstill works out better in terms of iteration performance<sup><a\r\nhref=\"#benchmarks\">[1]</a></sup> than every existing standard library container\r\nother than deque/vector, regardless of the ratio of erased to non-erased\r\nelements.</p>\r\n\r\n<p>Some more specific requirements for containers in the context of game\r\ndevelopment are listed in the <a href=\"#sg14gameengine\">appendix</a>.</p>\r\n\r\n<p>As another example, particle simulation (weather, physics etcetera) often\r\ninvolves large clusters of particles which interact with external objects and\r\neach other. The particles each have individual properties (spin, momentum,\r\ndirection etc) and are being created and destroyed continuously. Therefore the\r\norder of the particles is unimportant, what is important is the speed of\r\nerasure and insertion. No current standard library container has both strong\r\ninsertion and non-back erasure speed, so again this is a good match for\r\nhive.</p>\r\n\r\n<p><a href=\"https://groups.google.com/a/isocpp.org/forum/#!topic/sg14/1iWHyVnsLBQ\">Reports\r\nfrom other fields</a> suggest that, because most developers aren't aware of\r\ncontainers such as this, they often end up using solutions which are sub-par\r\nfor iterative performance such as std::map and std::list in order to preserve pointer\r\nvalidity, when most of their processing work is actually iteration-based. So,\r\nintroducing this container would both create a convenient solution to these\r\nsituations, as well as increasing awareness of better-performing approaches in\r\ngeneral. It will also ease communication across fields, as opposed to the\r\ncurrent scenario where each field uses a similar container but each has a\r\ndifferent name for it.</p>\r\n\r\n\r\n\r\n<h2><a id=\"impact\"></a>IV. Impact On the Standard</h2>\r\n\r\n<p>This is purely a library addition, requiring no changes to the language.</p>\r\n\r\n<h2><a id=\"design\"></a>V. Design Decisions</h2>\r\n\r\n<p>The three core aspects of a hive from an abstract perspective are: </p>\r\n<ol>\r\n  <li>A collection of element memory blocks + metadata, to prevent reallocation\r\n    during insertion (as opposed to a single memory block)</li>\r\n  <li>A method of skipping erased elements in O(1) time during iteration (as opposed to reallocating subsequent elements during erasure)</li>\r\n  <li>An erased-element location recording mechanism, to enable the re-use of\r\n    memory from erased elements in subsequent insertions, which in turn\r\n    increases cache locality and reduces the number of block\r\n    allocations/deallocations</li>\r\n</ol>\r\n\r\n<p>Each memory block houses multiple elements. The metadata about each block\r\nmay or may not be allocated with the blocks themselves (could be contained in a\r\nseparate structure). This metadata should include at a minimum, the number of\r\nnon-erased elements within each block and the block's capacity - which allows the\r\ncontainer to know when the block is empty and needs to be removed from the\r\niterative chain, and also allows iterators to judge when the end of one block\r\nhas been reached. A non-boolean method of skipping over\r\nerased elements during iteration while maintaining O(1) amortized iteration\r\ntime complexity is required (amortized due to block traversal, which would typically require a few more\r\noperations). Finally, a mechanism for keeping track of elements which have been\r\nerased must be present, so that those memory locations can be reused upon\r\nsubsequent element insertions.</p>\r\n\r\n<p>The following aspects of a hive must be implementation-defined in order to\r\nallow for variance and possible performance improvement, and to conform with\r\npossible changes to C++ in the future:</p>\r\n<ul>\r\n  <li>the method used to skip erased elements</li>\r\n  <li>time complexity of operations to update whatever metadata is associated with the skip method</li>\r\n  <li>erasure-recording mechanism</li>\r\n  <li>element memory block metadata</li>\r\n  <li>iterator structure</li>\r\n  <li>memory block growth factor</li>\r\n  <li>time complexity of advance()/next()/prev()</li>\r\n</ul>\r\n\r\n<p>However the implementation of these <em>is</em> significantly constrained by\r\nthe requirements of the container (lack of reallocation, stable pointers to\r\nnon-erased elements regardless of erasures/insertions).</p>\r\n\r\n<p>In terms of the <a href=\"https://plflib.org/colony.htm\">reference\r\nimplementation</a> the specific structure and mechanisms have changed many\r\ntimes over the course of development, however the interface to the container\r\nand its time complexity guarantees have remained largely unchanged (with the\r\nexception of the time complexity for updating skipfield nodes - which has not\r\nimpacted significantly on performance). So it is reasonably likely that\r\nregardless of specific implementation, it will be possible to maintain this\r\ngeneral specification without obviating future improvements in implementation,\r\nso long as time complexity guarantees for the above list are\r\nimplementation-defined.</p>\r\n\r\n<p>Below I explain the reference implementation's approach in terms of the\r\nthree core aspects described above, along with descriptions of some\r\nalternatives implementation approaches.</p>\r\n\r\n<h4>1. Collection of element memory blocks + metadata</h4>\r\n\r\n<p>In the reference implementation this is essentially a doubly-linked list of\r\n'group' structs containing (a) a dynamically-allocated element memory block, (b) memory block metadata and (c)\r\na dynamically-allocated skipfield. The memory blocks and skipfields have a growth factor of 2 from one\r\ngroup to the next. The metadata includes information necessary for an iterator\r\nto iterate over hive elements, such as the last insertion point within the\r\nmemory block, and other information useful to specific functions, such as the\r\ntotal number of non-erased elements in the node. This approach keeps the\r\noperation of freeing empty memory blocks from the hive container at O(1) time\r\ncomplexity. Further information is available <a\r\nhref=\"https://plflib.org/chained_group_allocation_pattern.htm\">here</a>.</p>\r\n\r\n<p>Using a vector of group structs with dynamically-allocated element memory blocks, using the swap-and-pop idiom where groups need to be erased from the iterative sequence, would not work. To explain, when a group becomes empty of elements, it must be removed from the sequence of groups, because otherwise you end up with highly-variable latency during iteration due to the need to skip over an unknown number of empty groups when traversing from one non-empty group to the next. Simply erasing the group will not suffice, as this would create a variable amount of latency during erasure when the group becomes empty, based on the number of groups after that group which would need to be reallocated backward in the vector. But even if one swapped the to-be-erased group with the back group, and then pop'd the to-be-erased group off the back, this would not solve the problem, as iterators require a stable pointer to the group they are traversing in order to traverse to the next group in the sequence. If an iterator pointed to an element in the back group, and the back group was swapped with the to-be-erased group, this would invalidate the iterator.</p>\r\n\r\n<p>A vector of pointers to group structs is more-possible. Erasing groups would still have highly-variable latency due to reallocation, however the cost of reallocating pointers may be negligible depending on architecture. While the number of pointers can be expected to be low in most cases due to the growth factor in memory blocks, if the user has defined their own memory block capacity limits the number of pointers could be large, and this has to be taken into consideration. In this case using a pop-and-swap idiom is still not possible, because while it would not necessarily invalidate the internal references of an iterator pointing to an element within the back group, the sequence of blocks would be changed and therefore the iterator would be moved backwards in the iterative sequence.</p>\r\n\r\n<p>A vector of memory blocks, as opposed to a vector of pointers to memory\r\nblocks or a vector of group structs with dynamically-allocated memory blocks, would also not work, both due to the above points and because as it would (a) disallow a growth factor in the memory\r\nblocks and (b) invalidate pointers to elements in subsequent blocks when a\r\nmemory block became empty of elements and was therefore removed from the\r\nvector. In short, negating hive's beneficial aspects.</p>\r\n\r\n\r\n<h4>2. A non-boolean method of skipping erased elements in O(1) time during iteration</h4>\r\n\r\n<p>The reference implementation currently uses a skipfield pattern called the\r\n<a href=\"https://plflib.org/matt_bentley_-_the_low_complexity_jump-counting_pattern.pdf\">Low complexity jump-counting pattern</a>. This effectively encodes the length of runs of consecutive erased elements, into a skipfield, which allows for O(1) time\r\ncomplexity during iteration. Since there is no branching involved in iterating\r\nover the skipfield aside from end-of-block checks, it can be less problematic\r\ncomputationally than a boolean skipfield (which has to branch for every\r\nskipfield read) in terms of CPUs which don't handle branching or\r\nbranch-prediction failure efficiently (eg. Core2). It also does not have the variable latency associated with a boolean skipfield.</p>\r\n\r\n<p>The pattern stores and modifies the run-lengths during insertion and erasure\r\nwith O(1) time complexity. It has a lot of similarities to the <a\r\nhref=\"https://plflib.org/matt_bentley_-_the_high_complexity_jump-counting_pattern.pdf\">High\r\ncomplexity jump-counting pattern</a>, which was a pattern previously used by\r\nthe reference implementation. Using the High complexity jump-counting pattern\r\nis an alternative, though the skipfield update time complexity guarantees for\r\nthat pattern are effectively undefined, or between O(1) and O(skipfield length)\r\nfor each insertion/erasure. In practice those updates result in one\r\nmemcpy operation which resolves to a single block-copy operation, but it is\r\nstill a little slower than the Low complexity jump-counting pattern. The\r\nmethod you use to skip erased elements will typically also have an effect on the type of\r\nmemory-reuse mechanism you can utilize.</p>\r\n\r\n<p>A pure boolean skipfield is not usable because it makes iteration time\r\ncomplexity undefined - it could for example result in thousands of branching\r\nstatements + skipfield reads for a single ++ operation in the case of many\r\nconsecutive erased elements. In the high-performance fields for which this\r\ncontainer was initially designed, this brings with it unacceptable latency.\r\nHowever another strategy using a combination of a jump-counting <i>and</i>\r\nboolean skipfield, which saves memory at the expense of computational\r\nefficiency, is possible as follows:</p>\r\n<ol>\r\n  <li>Instead of storing the data for the low complexity jump-counting pattern\r\n    in it's own skipfield, have a boolean bitfield indicating which elements\r\n    are erased. Store the jump-counting data in the erased element's memory\r\n    space instead (possibly alongside free list data).</li>\r\n  <li>When iterating, check whether the element is erased or not using the\r\n    boolean bitfield; if it is not erased, do nothing. If it is erased, read\r\n    the jump value from the erased element's memory space and skip forward the\r\n    appropriate number of nodes both in the element memory block and the\r\n    boolean bitfield.</li>\r\n</ol>\r\n\r\n<p>This approach has the advantage of still performing O(1) iterations from one\r\nnon-erased element to the next, unlike a pure boolean skipfield approach, but\r\ncompared to a pure jump-counting approach introduces 3 additional costs per\r\niteration via (1) a branch operation when checking the bitfield, (2) an\r\nadditional read (of the erased element's memory space) and (3) a bitmasking\r\noperation + bitshift to read the bit. But it does reduce the memory overhead of\r\nthe skipfield to 1 bit per-element, which reduces the cache load. An implementation and benchmarking would be required in order to establish how this approach compares to the current implementation's performance.</p>\r\n\r\n<p>Another method worth mentioning is the use of a referencing array - for example, having a vector of elements, together with a vector of either indexes or pointers to those elements. When an element is erased, the vector of elements itself is not updated - no elements are reallocated. Meanwhile the referencing vector is updated and the index or pointer to the erased element is erased. When iteration occurs it iterates over the referencing vector, accessing each element in the element vector via the indexes/pointers. The disadvantages of this technique are (a) much higher memory usage, particularly for small elements and (b) highly-variable latency during erasure due to reallocation in the referencing array. Since once of the goals of hive is predictable latency, this is likely not suitable.</p>\r\n\r\n<p><a href=\"http://bitsquid.blogspot.ca/2011/09/managing-decoupling-part-4-id-lookup.html\">Packed arrays</a> are not worth mentioning as the iteration method is considered separate from the referencing mechanism, making them unsuitable for a std:: container.</p>\r\n\r\n\r\n<h4>3. Erased-element location recording mechanism</h4>\r\n\r\n<p>There are two valid approaches here; both involve per-memory-block <a\r\nhref=\"https://en.wikipedia.org/wiki/Free_list\">free lists</a>, utilizing the\r\nmemory space of erased elements. The first approach forms a free list of all\r\nerased elements. The second forms a free list of the first element in each\r\n<i>run</i> of consecutive erased elements (\"skipblocks\", in terms of the\r\nterminology used in the jump-counting pattern papers). The second can be more\r\nefficient, but requires a doubly-linked free list rather than a singly-linked\r\nfree list, at least with a jump-counting skipfield - otherwise it would become an O(N) operation to update links in the\r\nskipfield, when a skipblock expands or contracts during erasure or\r\ninsertion.</p>\r\n\r\n<p>The reference implementation currently uses the second approach, using three\r\nthings to keep track of erased element locations:</p>\r\n<ol type=\"a\">\r\n  <li>Metadata for each memory block includes a 'next block with erasures'\r\n    pointer. The container itself contains a 'blocks with erasures' list-head\r\n    pointer. These are used by the container to create an intrusive\r\n    singly-linked list of memory blocks with erased elements which can be\r\n    re-used for future insertions.</li>\r\n  <li>Metadata for each memory block also includes a 'free list head' index\r\n    number, which records the index (within the memory block) of the first\r\n    element of the last-created skipblock - the 'head' skipblock.</li>\r\n  <li>The memory space of the first erased element in each skipblock is\r\n    reinterpret_cast'd via pointers as two index numbers, the first giving the\r\n    index of the previous skipblock in that memory block, the second giving the\r\n    index of the next skipblock in the sequence. In the case of the 'head'\r\n    skipblock in the sequence, a unique number is used for the 'next' index.\r\n    This forms a free list of runs of erased element memory locations which may\r\n    be re-used.</li>\r\n</ol>\r\n\r\n<p>Using indexes for next and previous links, instead of pointers, reduces the necessary bit-depth of the next and previous links, thereby reducing the necessary over-alignment of the container's element type. If a global (ie. all memory blocks) free list were used, pointers would be necessary, as hive is bidirectional and does not support the [ ] operator. This would potentially increase the necessary over-alignment of the element type to 128 bits for a doubly-linked free list. A global free list would also decrease cache locality when traversing the free list by jumping between memory blocks.</p>\r\n\r\n<p>Previous versions of the reference implementation used a singly-linked free\r\nlist of erased elements instead of a doubly-linked free list of skipblocks.\r\nThis was possible with the High complexity jump-counting pattern, but not\r\npossible using the Low complexity jump-counting pattern as it cannot calculate\r\na skipblock's start node location from a middle node's value like the High\r\ncomplexity pattern can. But using free-lists of skipblocks is a more efficient\r\napproach as it requires fewer free list nodes. In addition, re-using only the start or end nodes of a skipblock is faster because it never splits a single skipblock in two (which would require adding a new skipblock to the free list).</p>\r\n\r\n<p>One cannot use a stack of pointers (or similar) to erased elements for this\r\nmechanism, as early versions of the reference implementation did, because this\r\ncan create allocations during erasure, which changes the exception guarantees\r\nof erase(). One could instead scan all skipfields until an erased location was\r\nfound, or simply have the first item in the list above and then scan the first\r\navailable block, though both of these approaches would be slow.</p>\r\n\r\n<p>In terms of the alternative <i>boolean + jump-counting skipfield</i>\r\napproach described in the erased-element-skip-method section above, one could store both the\r\njump-counting data and free list data in any given erased element's memory\r\nspace, provided of course that elements are aligned to be wide enough to fit\r\nboth.</p>\r\n\r\n\r\n<h3>Implementation of iterator class</h3>\r\n\r\n<p>Any iterator implementation is going to be dependent on the erased-element-skipping mechanism used. The reference implementation's iterator stores a pointer to the current 'group' struct mentioned above, plus a pointer to the current element and a\r\npointer to its corresponding skipfield node. An alternative approach is to\r\nstore the group pointer + an index, since the index can indicate both the\r\noffset from the memory block for the element, as well as the offset from the\r\nstart of the skipfield for the skipfield node. However multiple implementations\r\nand benchmarks across many processors have shown this to be worse-performing\r\nthan the separate pointer-based approach, despite the increased memory cost for\r\nthe iterator class itself.</p>\r\n\r\n<p>++ operation is as follows, utilising the reference implementation's\r\nLow-complexity jump-counting pattern:</p>\r\n<ol>\r\n  <li>Add 1 to the existing element and skipfield pointers.</li>\r\n  <li>Dereference skipfield pointer to get value of skipfield node, add value\r\n    of skipfield node to both the skipfield pointer and the element pointer. If\r\n    the node is erased, its value will be a positive integer indicating the\r\n    number of nodes until the next non-erased node, if not erased it will be\r\n    zero.</li>\r\n  <li>If element pointer is now beyond end of element memory block, change\r\n    group pointer to next group, element pointer to the start of the next\r\n    group's element memory block, skipfield pointer to the start of the next\r\n    group's skipfield. In case there is a skipblock at the beginning of this\r\n    memory block, dereference skipfield pointer to get value of skipfield node\r\n    and add value of skipfield node to both the skipfield pointer and the\r\n    element pointer. There is no need to repeat the check for end of block, as\r\n    the block would have been removed from the iteration sequence if it were\r\n    empty of elements.</li>\r\n</ol>\r\n\r\n<p>-- operation is the same except both step 1 and 2 involve subtraction rather\r\nthan adding, and step 3 checks to see if the element pointer is now before the\r\nbeginning of the memory block. If so it traverses to the back of the previous\r\ngroup, and subtracts the value of the back skipfield node from the element\r\npointer and skipfield pointer.</p>\r\n\r\n<p>Iterators are bidirectional but also provide constant time\r\ncomplexity &gt;, &lt;, &gt;=, &lt;= and &lt;=&gt; operators for convenience\r\n(eg. in <code>for</code> loops when skipping over multiple elements per loop\r\nand there is a possibility of going past a pre-determined end element). This is\r\nachieved by keeping a record of the order of memory blocks. In the reference\r\nimplementation this is done by assigning a number to each memory block in its\r\nmetadata. In an implementation using a vector of pointers to memory blocks\r\ninstead of a linked list, one could use the position of the pointers within the\r\nvector to determine this. Comparing relative order of the two iterators' memory\r\nblocks via this number, then comparing the memory locations of the elements\r\nthemselves, if they happen to be in the same memory block, is enough to\r\nimplement all greater/lesser comparisons.</p>\r\n\r\n<h3>Additional notes on specific functions</h3>\r\n<ul>\r\n  <li><code style=\"font-weight:bold\">iterator insert</code> (all variants)<br>\r\n\r\n    <p>Insertion re-uses previously-erased element memory locations when\r\n    available, so position of insertion is effectively random unless no\r\n    previous erasures have occurred, in which case all elements will be\r\n    inserted linearly to the back of the container, at least in the current\r\n    implementation. These details have been removed from the standard in order\r\n    to allow leeway for potentially-better implementations in future - though\r\n    it is expected that a hive will always reuse erased memory locations, it\r\n    is impossible to predict optimal strategies for unknown future hardware.</p>\r\n</li>\r\n  <li><code style=\"font-weight:bold\">void insert</code> (all variants)<br>\r\n\r\n    <p>For range, fill and initializer_list insertion, it is not possible to guarantee that all the elements inserted will be sequential in the hive's iterative sequence, and therefore it is not considered useful to return an iterator to the first inserted element. There is a precedent for this in the various std:: map containers. Therefore these functions return void presently.</p>\r\n    <p>For range insert and range constructors, thhe syntax has been modified compared to other containers in order to take two potentially-different iterator types in order to support sentinels and the like.</p>\r\n</li>\r\n\r\n  <li><code style=\"font-weight:bold\">iterator erase</code> (all variants)<br>\r\n  <p>Firstly it should be noted that erase may retain memory blocks which become completely empty of elements due to erasures, adding them to the set of unused memory blocks which are normally created by reserve(). Under what circumstances these memory blocks are retained rather than deallocated is implementation-defined - however given that small memory blocks have low cache locality compared to larger ones, from a performance perspective it is best to only retain the larger of the blocks currently allocated in the hive. In most cases this would mean the back block would almost always be retained. There is a lot of nuance to this, and it's also a matter of trading off complexity of implementation vs actual benchmarked speed vs latency. In my tests retaining both back blocks and 2nd-to-back blocks while ignoring actual capacity of blocks seems to have the best overall performance characteristics.</p>\r\n  <p>There are three major performance advantages to retaining back blocks as opposed to any block - the first is that these will be, under most circumstances, the largest blocks in the hive (given the built-in growth factor) - the only exception to this is when splice is used, which may result in a smaller block following a larger block (implementation-dependent). Larger blocks == more cache locality during iteration, large numbers of erased elements notwithstanding. The second advantage is that in situations where elements are being inserted to and erased from the back of the hive (this assumes no erased element locations in other memory blocks, which would otherwise be used for insertions) continuously and in quick succession, retaining the back block avoids large numbers of deallocations/reallocations. The third advantage is that deallocations of larger blocks can, in part, be moved to non-critical code regions via trim(). Though ultimately if the user wants total control of when allocations and deallocations occur they would want to use a custom allocator.</p>\r\n<p>Lastly, specifying a return iterator for range-erase may seem pointless, as no reallocation of elements occurs in erase so the return iterator will almost always be the <code>last</code> iterator of the <code>const_iterator first, const_iterator last</code> pair. However if <code>last</code> was <code>end()</code>, the new value of <code>end()</code> (if it has changed due to empty block removal) will be returned. In this case either the user submitted <code>end()</code> as <code>last</code>, or they incremented an iterator pointing to the final element in the hive and submitted that as <code>last</code>. The latter is the only valid reason to return an iterator from the function, as it may occur as part of a loop which is erasing elements and ends when <code>end()</code> is reached. If <code>end()</code> is changed by the erasure of an entire memory block, but the iterator being used in the loop does not accurately reflect <code>end()</code>'s new value, that iterator could iterate past <code>end()</code> and the loop would never finish.</li>\r\n\r\n      <li><code style=\"font-weight:bold\">void reshape(std::hive_limits block_capacity_limits);</code><br>\r\n\t\t  <p>This function updates the block capacity limits in the hive and, if necessary, changes any blocks which fall outside of those limits to be within the limits. For this reason it may trigger an exception with non-copyable/movable types, and also invalidate pointers/iterators/etc to elements.</p>\r\n        <p>The order of elements post-reshape is not guaranteed to be stable in\r\n        order to allow for optimizations. Specifically in the instance where a\r\n        given element memory block no longer fits within the limits supplied by\r\n        the user, depending on the state of the hive as a whole, the elements\r\n        within that memory block could be reallocated to previously-erased\r\n        element locations in other memory blocks which do fit within the\r\n        supplied limits. Or they could be reallocated to the back of the final memory block.</p>\r\n        <p>Additionally if there is empty capacity at the back of the last\r\n        block in the container, at least some of the elements could be moved to\r\n        that position rather than being reallocated to a new memory block. Both\r\n        of these techniques increase cache locality by removing skipped memory\r\n        spaces within existing memory blocks. However whether they are used is\r\n        implementation-dependent.</p>\r\n      </li>\r\n      <li><code style=\"font-weight:bold\">iterator get_iterator(pointer p) noexcept;<br>\r\n\t\tconst_iterator get_iterator(const_pointer p) const noexcept;</code><br>\r\n        <p>Because hive iterators are likely to be large, storing three\r\n        pieces of data - current memory block, current element within memory\r\n        block and potentially, current skipfield node - a program storing many\r\n        links to elements within a hive may opt to dereference iterators to\r\n        get pointers and store those instead of iterators, to save memory. This\r\n        function reverses the process, giving an iterator which can then be\r\n        used for operations such as erase. get_const_iterator was fielded as a workaround for the possibility of someone wanting to supply a non-const pointer\r\n\t\t  and get a const_iterator back, however <code>as_const</code> fulfills this same role when supplied to get_iterator and doesn't require expanding the interface of hive.</p>\r\n      </li>\r\n      <li><code style=\"font-weight:bold\">void shrink_to_fit();</code>\r\n        <p>A decision had to be made as to whether this function should, in the\r\n        context of hive, be allowed to reallocate elements (as std::vector\r\n        does) or simply trim off unused memory blocks (as std::deque does). Due\r\n        to the fact that a large hive memory block could have as few as one\r\n        remaining element after a series of erasures, it makes little sense to\r\n        only trim unused blocks, and instead a shrink_to_fit is expected to\r\n        reallocate all non-erased elements to as few memory blocks as possible\r\n        in order to increase cache locality during iteration and reduce memory\r\n        use. As with reshape(), the order of elements post-reshape is not\r\n        guaranteed to be stable, to allow for potential optimizations. The\r\n        trim() command is also introduced as a way to free unused memory blocks\r\n        which have been previously reserved, without reallocating elements and\r\n        invalidating iterators.</p>\r\n      </li>\r\n      <li><code style=\"font-weight:bold\">void sort();</code>\r\n\t\t  <p>It is forseen that although the container has unordered insertion, there may be circumstances where sorting is desired. Because hive uses bidirectional iterators, using std::sort or similar is not possible. Therefore an internal sort routine is warranted, as it is with std::list. An implementation of the sort routine used in the reference implementation of hive can be found in a non-container-specific form at <a href=\"https://plflib.org/indiesort.htm\">plflib.org/indiesort.htm</a> - see that page for the technique's advantages over the usual sort algorithms for non-random-access containers. Unfortunately to date there has been no interest in including this algorithm in the standard library. An allowance is made for sort to allocate memory if necessary, so that algorithms such as indiesort can be used internally.</p>\r\n\t\t</li>\r\n      <li><code style=\"font-weight:bold\">void splice(hive &amp;x);</code>\r\n        <p>Whether <code>x</code>'s blocks are transferred to the beginning or\r\n        end of <code>*this</code>'s iterative sequence, or interlaced in some way (for example, to preserve relative capacity growth-factor ordering of subsequent blocks) is implementation-defined. Better\r\n        performance may be gained in some cases by allowing the source blocks\r\n        to go to the front rather than the back, depending on how full the\r\n        final block in <code>x</code>'s iterative sequence is. This is because\r\n        unused elements that are not at the back of hive's iterative sequence\r\n        will need to be marked as skipped, and skipping over large numbers of\r\n        elements will incur a small performance disadvantage during iteration\r\n        compared to skipping over a small number of elements, due to memory\r\n        locality.</p>\r\n        <p>This function is not noexcept for three reasons - the first is that a length_error exception may be thrown if any of the capacities of the source <code>x</code>'s blocks are outside of the range defined by the destination's (<code>*this</code>) minimum and maximum block capacity limits. Second is that an exception may be thrown if the allocators of the two hives are different. Third is that in the case of an implementation using a linked list of group structs (ala the reference implementation) transferring blocks involves no allocation, however in the case of an implementation using a vector of pointers to blocks, an additional allocation may have to be made if the group pointer vector isn't of sufficient capacity to accomodate pointers to the spliced blocks from the source.</p>\r\n      </li>\r\n      <li><code style=\"font-weight:bold\">size_type memory() const noexcept;</code>\r\n\t\t  <p>A hive uses memory block metadata and may use a skipfield, both which are\r\n        implementation-defined, so it is not possible for a user to estimate\r\n        internal memory usage from size(), sizeof() or capacity(). This function fulfills\r\n        that role. Because some types of elements may allocate their own memory\r\n        dynamically (eg. std::hive&lt;std::vector&gt;) only the static\r\n        allocation of each element is included in this functions byte count.</p>\r\n      <p>This function can be made constant time by adding a counter to the hive that keeps track of the number of reserved memory blocks available, or by having a vector of pointers to memory blocks instead an intrusive linked list of memory blocks. However in the case of the reference implementation which uses linked lists, the counter metadata would only be used by this function and since this function is not expected to be in heavy use, the time complexity of this function is left as implementation-defined to allow flexibility.</p>\r\n\t\t</li>\r\n      <li>Non-member function overloads for <code style=\"font-weight:bold\">advance, prev and next</code> (all variants)<br>\r\n\r\n        <p>For these functions, complexity is dependent on state of hive, position of iterator and\r\n        amount of distance, but in many cases will be less than linear, and may\r\n        be constant. To explain: it is necessary in a hive to store metadata\r\n        both about the capacity of each block (for the purpose of iteration)\r\n        and how many non-erased elements are present within the block (for the\r\n        purpose of removing blocks from the iterative chain once they become\r\n        empty). For this reason, intermediary blocks between the iterator's\r\n        initial block and its final destination block (if these are not the\r\n        same block, and if the initial block and final block are not\r\n        immediately adjacent) can be skipped rather than iterated linearly\r\n        across, by using the \"number of non-erased elements\" metadata.</p>\r\n        <p>This means that the only linear time operations are any iterations\r\n        within the initial block and the final block. However if either the\r\n        initial or final block have no erased elements (as determined by\r\n        comparing whether the block's capacity metadata and the block's \"number\r\n        of non-erased elements\" metadata are equal), linear iteration can be\r\n        skipped for that block and pointer/index math used instead to determine\r\n        distances, reducing complexity to constant time. Hence the best case\r\n        for this operation is constant time, the worst is linear to the\r\n        distance.</p>\r\n      </li>\r\n      <li>Non-member function overloads for <code style=\"font-weight:bold\">distance</code> (all variants)<br>\r\n\r\n        <p>The same considerations which apply to advance, prev and next also\r\n        apply to distance - intermediary blocks between first and last's blocks\r\n        can be skipped in constant time and their \"number of non-erased\r\n        elements\" metadata added to the cumulative distance count, while\r\n        first's block and last's block (if they are not the same block) must be\r\n        linearly iterated across unless either block has no erased elements, in\r\n        which case the operation becomes pointer/index math and is reduced to\r\n        constant time for that block. In addition, if first's block is not the\r\n        same as last's block, and last is equal to end() or --end(), or is the\r\n        last element in that block, last's block's elements can also counted\r\n        from the \"number of non-erased elements\" metadata rather than via\r\n        iteration.</p>\r\n      </li>\r\n      <li>Priority template parameter for the container<br>\r\n      <p>This forms a non-binding request for the container to prioritize either performance or memory use, supplied in the form of a scoped enum. The reference implementation uses a regular un-scoped enum, as it must also work under C++03. In terms of the reference implementation the priority parameter changes the skipfield type from unsigned short (performance) to unsigned char (memory use) - which in turn changes the maximum block limits, because in the reference implementation the block capacities are limited to numeric_limits&lt;skipfield_type&gt;::max. The maximum block capacity limit affects iteration performance, due to a greater or lesser number of elements being able to be sequential in memory, and the subsequent effects on cache. For small numbers of elements ie. under 1000, unsigned char also will be faster in addition to needing less memory, due to the lowered cache usage and the fact that the maximum block capacity limit is not significantly limiting cache locality at this point. Hence, prioritizing for performance may not necessarily be faster in all circumstances, but should be faster in most - if in fact the request is actioned upon, and it is not guaranteed to be actioned upon in all implementations.</p>\r\n      <p>There is a point of diminishing returns in terms of how many elements can be stored sequentially in memory and how that impacts performance, due to the limits of cache size - hence it was found that increasing the skipfield type to unsigned int and thence increasing the block capacity limit, did not have a performance advantage on any number of elements.</p>\r\n      </li>\r\n\r\n    </ul>\r\n\r\n\r\n\t<h3>Results of implementation</h3>\r\n\r\n  <p>In practical application the reference implementation is generally faster\r\n  for insertion and (non-back) erasure than current standard library\r\n  containers, and generally faster for iteration than any container except\r\n  vector and deque. For full details, see <a href=\"#benchmarks\">benchmarks</a>.</p>\r\n\r\n\r\n  <h2><a id=\"technical\"></a>VI. Technical Specification</h2>\r\n\r\n  <p>Suggested location of hive in the standard is 22.3, Sequence\r\n  Containers.</p>\r\n\r\n  <h3>22.3.7 Header <code>&lt;hive&gt;</code> synopsis [hive.syn]</h3>\r\n\r\n  <div style=\"background: #ffffff; overflow:auto; width:auto; border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\">\r\n  <pre style=\"margin: 0; line-height: 125%\">\r\n#include &lt;initializer_list&gt; // see 17.10.2\r\n#include &lt;compare&gt; // see 17.11.1\r\n#include &lt;concepts&gt; // see 18.3\r\n#include &lt;stdexcept&gt; // see 19.2\r\n#include &lt;utility&gt; // see 20.2.1\r\n#include &lt;memory&gt; // see 20.10\r\n\r\nnamespace std {\r\n   // 22.3.14, class template hive\r\n\r\n\tstruct hive_limits;\r\n\tenum class hive_priority;\r\n\r\n   template &lt;class T, class Allocator = allocator&lt;T&gt;, hive_priority priority = hive_priority::performance&gt; class hive;\r\n\r\n   namespace pmr {\r\n      template &lt;class T&gt;\r\n      using hive = std::hive&lt;T, polymorphic_allocator&lt;T&gt;&gt;;\r\n   }\r\n}</pre>\r\n  </div>\r\n\r\n  <h4><a id=\"iteratorinvalidation\"></a>Iterator Invalidation</h4>\r\n\r\n  <table border=\"1\">\r\n    <tbody>\r\n      <tr>\r\n        <td>All read-only operations, swap, std::swap, splice, operator=\r\n          &amp;&amp; (source), reserve, trim</td>\r\n        <td>Never.</td>\r\n      </tr>\r\n      <tr>\r\n        <td>clear, operator= &amp; (destination), operator= &amp;&amp;\r\n          (destination)</td>\r\n        <td>Always.</td>\r\n      </tr>\r\n      <tr>\r\n        <td>reshape</td>\r\n        <td>Only if memory blocks exist whose capacities do not fit within the\r\n          supplied limits.</td>\r\n      </tr>\r\n      <tr>\r\n        <td>shrink_to_fit</td>\r\n        <td>Only if capacity() != size().</td>\r\n      </tr>\r\n      <tr>\r\n        <td>erase</td>\r\n        <td>Only for the erased element. If an iterator is == end() it may be\r\n          invalidated if the back element of the hive is erased (similar to\r\n          deque (22.3.9)).\r\n\t\t\t Likewise if a reverse_iterator is == rend() it may be invalidated if the front element of the hive is erased.\r\n\t\t\t The same applies with cend() and crend() for const_iterator and const_reverse_iterator respectively.\r\n\t\t\t </td>\r\n      </tr>\r\n      <tr>\r\n        <td>insert, emplace</td>\r\n        <td>If an iterator is == end() or == begin() it may be invalidated by a subsequent insert/emplace.\r\n\t\t  \t\tLikewise if a reverse_iterator is == rend() or == rbegin() it may be\r\n          invalidated by a subsequent insert/emplace.\r\n\t\t\t The same rules apply with cend(), cbegin() and crend(), crbegin() for const_iterator and const_reverse_iterator respectively.\r\n\t\t\t </td>\r\n      </tr>\r\n    </tbody>\r\n  </table>\r\n\r\n\r\n  <h3>22.3.14 Class template <code>hive</code> [hive]</h3>\r\n\r\n  <h4>22.3.14.1 Class template <code>hive</code> overview [hive.overview]</h4>\r\n<ol>\r\n  <li>A hive is a sequence container that allows constant-time insert and\r\n    erase operations. Insertion location is the back of the container when no\r\n    erasures have occured. When erasures have occured it will re-use existing\r\n    erased element memory spaces where possible and insert to those locations.\r\n    Storage management is handled automatically and is specifically organized\r\n    in multiple blocks of sequential elements. Unlike vectors (22.3.12) and\r\n    deques (22.3.9), fast random access to hive elements is not supported,\r\n    but specializations of advance/next/prev give access which can be\r\n    better than linear time in the number of elements traversed.</li>\r\n  <li>Erasures are processed using implementation-defined strategies for skipping erased elements during iteration, rather than reallocating subsequent elements as is expected in a vector or deque.</li>\r\n  <li>Memory block element capacities have an implementation-defined growth\r\n    factor, for example a new block's capacity could be equal to the summed capacities of the existing\r\n    blocks.</li>\r\n  <li>Limits can be placed on the minimum and maximum element capacities of\r\n    memory blocks, both by a user and by an implementation. Minimum capacity\r\n    shall be no more than maximum capacity. When limits are not specified by a\r\n    user, the implementation's default limits are used. Where user-specified limits do\r\n    not fit within the implementation's limits (ie. user minimum is less than\r\n    implementation minimum or user maximum is more than implementation maximum)\r\n    an exception is thrown. User-specified limits can be supplied to a\r\n    constructor or to the reshape() function, using the\r\n    <code>std::hive_limits</code> struct with its <code>min</code> and\r\n    <code>max</code> members set to the minimum and maximum element capacity\r\n    limits respectively. The current limits in a hive instance can be\r\n    obtained from block_capacity_limits().</li>\r\n  <li>A hive satisfies all of the requirements of a container, of a\r\n    reversible container (given in two tables in 22.2), of a sequence\r\n    container, including most of the optional sequence container requirements\r\n    (22.2.3), and of an allocator-aware container (Table 78). The exceptions\r\n    are the <code>operator[]</code> and <code>at</code> member functions, which\r\n    are not provided.</li>\r\n  <li>hive iterators satisfy bidirectional requirements but also provide\r\n    relational operators &lt;, &lt;=, &gt;, &gt;= and &lt;=&gt; which compare\r\n    the relative ordering of two iterators in the sequence of a hive\r\n  instance.</li>\r\n  <li>Iterator operations ++ and -- take constant amortized time, other iterator operations take constant time.</li>\r\n</ol>\r\n<code>template &lt;class T, class Allocator = std::allocator&lt;T&gt;, priority Priority = priority::performance&gt; class hive</code>\r\n\r\n<p><code><b>T</b></code> - the element type. In general T shall meet the\r\nrequirements of <a\r\nhref=\"https://en.cppreference.com/w/cpp/named_req/Erasable\">Erasable</a>, <a\r\nhref=\"https://en.cppreference.com/w/cpp/named_req/CopyAssignable\">CopyAssignable</a>\r\nand <a\r\nhref=\"https://en.cppreference.com/w/cpp/named_req/CopyConstructible\">CopyConstructible</a>.<br>\r\nHowever, if emplace is utilized to insert elements into the hive, and no\r\nfunctions which involve copying or moving are utilized, T is only required to\r\nmeet the requirements of <a href=\"https://en.cppreference.com/w/cpp/named_req/Erasable\">Erasable</a>.<br>\r\nIf move-insert is utilized instead of emplace, T shall also meet the\r\nrequirements of <a\r\nhref=\"https://en.cppreference.com/w/cpp/named_req/MoveConstructible\">MoveConstructible</a>.<br>\r\n<br>\r\n<code><b>Allocator</b></code> - an allocator that is used to acquire memory to\r\nstore the elements. The type shall meet the requirements of <a\r\nhref=\"https://en.cppreference.com/w/cpp/named_req/Allocator\">Allocator</a>. The\r\nbehavior is undefined if <code>Allocator::value_type</code> is not the same as\r\nT.<br>\r\n<br>\r\n<code><b>Priority</b></code> - if set to <code>priority::memory_use</code> this is a non-binding request to prioritize lowered memory usage over container performance. [ Note: The request is non-binding to allow latitude for implementation-specific optimizations. If this feature is implemented, it is <i>not</i> specified that the container shall have better performance when using priority::performance instead of priority::memory_usage in <i>all</i> scenarios, but that it shall have better performance in <i>most</i> scenarios. - end note ]</p>\r\n\r\n<div style=\"background: #ffffff; overflow:auto; width:auto; border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\">\r\n<pre style=\"margin: 0; line-height: 125%\">namespace std {\r\n\r\nstruct hive_limits\r\n{\r\n\tsize_t min, max;\r\n\thive_limits(size_t minimum, size_t maximum) noexcept : min(minimum), max(maximum) {}\r\n};\r\n\r\n\r\nenum struct hive_priority { performance, memory_use };\r\n\r\n\r\ntemplate &lt;class T, class Allocator = allocator&lt;T&gt;, hive_priority Priority = hive_priority::performance&gt;\r\nclass hive {\r\npublic:\r\n\r\n  // types\r\n  using value_type = T;\r\n  using allocator_type = Allocator;\r\n  using pointer = typename allocator_traits&lt;Allocator&gt;::pointer;\r\n  using const_pointer = typename allocator_traits&lt;Allocator&gt;::const_pointer;\r\n  using reference = value_type&amp;;\r\n  using const_reference = const value_type&amp;;\r\n  using size_type = implementation-defined; // see 22.2\r\n  using difference_type = implementation-defined; // see 22.2\r\n  using iterator = implementation-defined; // see 22.2\r\n  using const_iterator = implementation-defined; // see 22.2\r\n  using reverse_iterator = implementation-defined; // see 22.2\r\n  using const_reverse_iterator = implementation-defined; // see 22.2\r\n\r\n\r\n\r\n  hive() noexcept(noexcept(Allocator())) : hive(Allocator()) { }\r\n  explicit hive(std::hive_limits block_capacity_limits) noexcept(noexcept(Allocator())) : hive(Allocator()) { }\r\n  explicit hive(const Allocator&amp;) noexcept;\r\n  explicit hive(std::hive_limits block_capacity_limits, const Allocator&amp;) noexcept;\r\n  explicit hive(size_type n, std::hive_limits block_capacity_limits = implementation-defined, const Allocator&amp; = Allocator());\r\n  hive(size_type n, const T&amp; value, std::hive_limits block_capacity_limits = implementation-defined, const Allocator&amp; = Allocator());\r\n  template&lt;class InputIterator1, class InputIterator2&gt;\r\n    hive(InputIterator1 first, InputIterator2 last, std::hive_limits block_capacity_limits = implementation-defined, const Allocator&amp; = Allocator());\r\n  hive(const hive&amp; x);\r\n  hive(hive&amp;&amp;) noexcept;\r\n  hive(const hive&amp;, const Allocator&amp;);\r\n  hive(hive&amp;&amp;, const Allocator&amp;);\r\n  hive(initializer_list&lt;T&gt;, std::hive_limits block_capacity_limits = implementation-defined, const Allocator&amp; = Allocator());\r\n  ~hive() noexcept;\r\n  hive&amp; operator= (const hive&amp; x);\r\n  hive&amp; operator= (hive&amp;&amp; x) noexcept(allocator_traits&lt;Allocator&gt;::propagate_on_container_move_assignment::value || allocator_traits&lt;Allocator&gt;::is_always_equal::value);\r\n  hive&amp; operator= (initializer_list&lt;T&gt;);\r\n  template&lt;class InputIterator1, class InputIterator2&gt; void assign(InputIterator1 first, InputIterator2 last);\r\n  void assign(size_type n, const T&amp; t);\r\n  void assign(initializer_list&lt;T&gt;);\r\n  allocator_type get_allocator() const noexcept;\r\n\r\n\r\n\r\n  // iterators\r\n  iterator               begin() noexcept;\r\n  const_iterator         begin() const noexcept;\r\n  iterator               end() noexcept;\r\n  const_iterator         end() const noexcept;\r\n  reverse_iterator       rbegin() noexcept;\r\n  const_reverse_iterator rbegin() const noexcept;\r\n  reverse_iterator       rend() noexcept;\r\n  const_reverse_iterator rend() const noexcept;\r\n\r\n  const_iterator         cbegin() const noexcept;\r\n  const_iterator         cend() const noexcept;\r\n  const_reverse_iterator crbegin() const noexcept;\r\n  const_reverse_iterator crend() const noexcept;\r\n\r\n\r\n  // capacity\r\n  [[nodiscard]] bool empty() const noexcept;\r\n  size_type size() const noexcept;\r\n  size_type max_size() const noexcept;\r\n  size_type capacity() const noexcept;\r\n  size_type memory() const noexcept;\r\n  void reserve(size_type n);\r\n  void shrink_to_fit();\r\n  void trim() noexcept;\r\n\r\n\r\n  // modifiers\r\n  template &lt;class... Args&gt; iterator emplace(Args&amp;&amp;... args);\r\n  iterator insert(const T&amp; x);\r\n  iterator insert(T&amp;&amp; x);\r\n  void insert(size_type n, const T&amp; x);\r\n  template &lt;class InputIterator1, class InputIterator2&gt; void insert(InputIterator1 first, InputIterator2 last);\r\n  void insert(initializer_list&lt;T&gt; il);\r\n  iterator erase(const_iterator position);\r\n  iterator erase(const_iterator first, const_iterator last);\r\n  void swap(hive&amp;) noexcept(allocator_traits&lt;Allocator&gt;::propagate_on_container_swap::value || allocator_traits&lt;Allocator&gt;::is_always_equal::value);\r\n  void clear() noexcept;\r\n\r\n\r\n  // hive operations\r\n  void splice(hive &amp;x);\r\n\r\n  std::hive_limits block_capacity_limits() const noexcept;\r\n  void reshape(std::hive_limits block_capacity_limits);\r\n\r\n  iterator get_iterator(pointer p) noexcept;\r\n  const_iterator get_iterator(const_pointer p) const noexcept;\r\n\r\n  void sort();\r\n  template &lt;class Compare&gt; void sort(Compare comp);\r\n\r\n  friend bool operator== (const hive &amp;x, const hive &amp;y);\r\n  friend bool operator!= (const hive &amp;x, const hive &amp;y);\r\n\r\n\r\n  class iterator\r\n  {\r\n    friend void advance(iterator &amp;it, Distance n);\r\n    friend iterator next(iterator it, difference_type distance = 1);\r\n    friend iterator prev(iterator it, difference_type distance = 1);\r\n    friend difference_type distance(iterator first, iterator last);\r\n  }\r\n\r\n\r\n  class const_iterator\r\n  {\r\n    friend void advance(const_iterator &amp;it, Distance n);\r\n    friend const_iterator next(const_iterator it, difference_type distance = 1);\r\n    friend const_iterator prev(const_iterator it, difference_type distance = 1);\r\n    friend difference_type distance(const_iterator first, const_iterator last);\r\n  }\r\n\r\n\r\n  class reverse_iterator\r\n  {\r\n    friend void advance(reverse_iterator &amp;it, Distance n);\r\n    friend reverse_iterator next(reverse_iterator it, difference_type distance = 1);\r\n    friend reverse_iterator prev(reverse_iterator it, difference_type distance = 1);\r\n    friend difference_type distance(reverse_iterator first, reverse_iterator last);\r\n  }\r\n\r\n\r\n  class const_reverse_iterator\r\n  {\r\n    friend void advance(const_reverse_iterator &amp;it, Distance n);\r\n    friend const_reverse_iterator next(const_reverse_iterator it, difference_type distance = 1);\r\n    friend const_reverse_iterator prev(const_reverse_iterator it, difference_type distance = 1);\r\n    friend difference_type distance(const_reverse_iterator first, const_reverse_iterator last);\r\n  }\r\n\r\n\r\n  // swap\r\n  friend void swap(hive&amp; x, hive&amp; y)\r\n    noexcept(noexcept(x.swap(y)));\r\n\r\n\r\n  // erase\r\n  template &lt;class Predicate&gt;\r\n    friend size_type erase_if(hive&amp; c, Predicate pred);\r\n  template &lt;class U&gt;\r\n    friend size_type erase(hive&amp; c, const U&amp; value);\r\n}\r\n\r\n\r\ntemplate&lt;class InputIterator, class Allocator = allocator&lt;iter-value-type &lt;InputIterator&gt;&gt;&gt;\r\n  hive(InputIterator, InputIterator, Allocator = Allocator())\r\n    -> hive&lt;iter-value-type &lt;InputIterator&gt;, Allocator&gt;;\r\n\r\n</pre>\r\n</div>\r\n\r\n\r\n<h4>22.3.14.2 hive constructors, copy, and assignment [hive.cons]</h4>\r\n<code style=\"font-weight:bold\">explicit hive(const Allocator&amp;);</code>\r\n<ol>\r\n  <li>Effects: Constructs an empty hive, using the specified allocator.</li>\r\n  <li>Complexity: Constant.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">explicit hive(size_type n, const T&amp; value, std::hive_limits block_capacities = implementation-defined, const Allocator&amp; =Allocator());</code>\r\n<ol start=\"3\">\r\n  <li>Preconditions: <code>T</code> shall be <i>Cpp17MoveInsertable</i> into\r\n    <code>*this</code>.</li>\r\n  <li>Effects: Constructs a hive with n copies of <code>value</code>, using\r\n    the specified allocator.</li>\r\n  <li>Complexity: Linear in n.</li>\r\n  <li>Throws: <code>length_error</code> if <code>block_capacities.min</code> or\r\n    <code>block_capacities.max</code> are outside the implementation's minimum\r\n    and maximum element memory block capacity limits, or if\r\n    <code>block_capacities.min &gt; block_capacities.max</code>.\r\n  <li>Remarks: If <code>n</code> is larger than\r\n    <code>block_capacities.min</code>, the capacity of the first block created\r\n    will be the smaller of <code>n</code> or <code>block_capacities.max</code>.</li>\r\n</ol>\r\n<br>\r\n\r\n<pre><code style=\"font-weight:bold\">template &lt;class InputIterator1, class InputIterator2&gt;\r\n  hive(InputIterator1 first, InputIterator2 last, std::hive_limits block_capacities = implementation-defined, const Allocator&amp; = Allocator());</code></pre>\r\n<ol start=\"8\">\r\n  <li>Preconditions: <code>InputIterator1</code> shall be <code>std::equality_comparable_with InputIterator2</code>.</li>\r\n  <li>Effects: Constructs a hive equal to the range [first, last), using the\r\n    specified allocator.</li>\r\n  <li>Complexity: Linear in distance(first, last).</li>\r\n  <li>Throws: <code>length_error</code> if <code>block_capacities.min</code> or\r\n    <code>block_capacities.max</code> are outside the implementation's minimum\r\n    and maximum element memory block capacity limits, or if\r\n    <code>block_capacities.min &gt; block_capacities.max</code>. Or\r\n  <li>Remarks: If iterators are random-access, let <code>n</code> be last -\r\n    first; if <code>n</code> is larger than <code>block_capacities.min</code>,\r\n    the capacity of the first block created will be the smaller of\r\n    <code>n</code> or <code>block_capacities.max</code>.</li>\r\n</ol>\r\n\r\n\r\n<h4>22.3.14.3 hive capacity [hive.capacity]</h4>\r\n\r\n<code style=\"font-weight:bold\">size_type capacity() const noexcept;</code>\r\n<ol>\r\n  <li>Returns: The total number of elements that the hive can currently\r\n    contain without needing to allocate more memory blocks.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">size_type memory() const noexcept;</code>\r\n<ol start=\"2\">\r\n  <li>Returns: The memory use, in bytes, of the container as a whole,\r\n    including elements but not including any dynamic allocation incurred by\r\n    those elements.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">void reserve(size_type n);</code>\r\n<ol start=\"3\">\r\n  <li>Effects: A directive that informs a hive of a planned change in size,\r\n    so that it can manage the storage allocation accordingly. Since minimum and\r\n    maximum memory block sizes can be specified by users, after\r\n    <code>reserve()</code>, <code>capacity()</code> is not guaranteed to be\r\n    equal to the argument of <code>reserve()</code>, may be greater. Does not\r\n    cause reallocation of elements.</li>\r\n  <li>Complexity: It does not change the size of the sequence and creates at\r\n    most <code>(n / block_capacity_limits().max) + 1</code> allocations.</li>\r\n  <li>Throws: <code>length_error</code> if <code>n &gt; max_size()</code><sup><a href=\"#r223\">223</a></sup>.</li>\r\n</ol>\r\n<p style=\"font-size: 90%\"><a id=\"r223\"></a>223) reserve() uses Allocator::allocate() which may throw an appropriate exception.</p>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">void shrink_to_fit();</code>\r\n<ol start=\"6\">\r\n  <li>Preconditions: <code>T</code> is <i>Cpp17MoveInsertable</i> into\r\n    <code>*this</code>.</li>\r\n  <li>Effects: shrink_to_fit is a non-binding request to reduce\r\n    <code>capacity()</code> to be closer to <code>size()</code>. [ Note: The\r\n    request is non-binding to allow latitude for implementation-specific\r\n    optimizations. - end note ] It does not increase <code>capacity()</code>,\r\n    but may reduce <code>capacity()</code> by causing reallocation. It may move\r\n    elements from multiple memory blocks and consolidate them into a smaller\r\n    number of memory blocks.<br>\r\n    If an exception is thrown other than by the move constructor of a\r\n    non-<em>Cpp17CopyInsertable</em> T, there are no effects.</li>\r\n  <li>Complexity: If reallocation happens, linear to the number of elements\r\n    reallocated.</li>\r\n  <li>Remarks: Reallocation invalidates all the references, pointers, and\r\n    iterators referring to the elements reallocated as well as the past-the-end\r\n    iterator. [Note: If no reallocation happens, they remain valid. &mdash;end\r\n    note] The order of elements post-operation is not guaranteed to be stable.\r\n  </li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">void trim();</code>\r\n<ol start=\"10\">\r\n  <li>Effects: Removes and deallocates empty memory blocks created by prior\r\n    calls to <code>reserve()</code> or <code>erase()</code>. If such memory\r\n    blocks are present, <code>capacity()</code> will be reduced.</li>\r\n  <li>Complexity: Linear in the number of reserved blocks to deallocate.</li>\r\n  <li>Remarks: Does not reallocate elements and no references, pointers or\r\n    iterators referring to elements in the sequence will be invalidated.</li>\r\n</ol>\r\n<br>\r\n\r\n\r\n\r\n<h4>22.3.14.4 hive modifiers [hive.modifiers]</h4>\r\n<pre><code style=\"font-weight:bold\">iterator insert(const T&amp; x);\r\niterator insert(T&amp;&amp; x);\r\nvoid insert(size_type n, const T&amp; x);\r\ntemplate &lt;class InputIterator1, class InputIterator2&gt;\r\n  void insert(InputIterator1 first, InputIterator2 last);\r\nvoid insert(initializer_list&lt;T&gt;);\r\ntemplate &lt;class... Args&gt;\r\n  iterator emplace(Args&amp;&amp;... args);</code></pre>\r\n<ol>\r\n  <li>Preconditions: For <code>template &lt;class InputIterator1, class InputIterator2&gt; void insert(InputIterator1 first, InputIterator2 last)</code>, <code>InputIterator1</code> shall be <code>std::equality_comparable_with InputIterator2</code>.</li>\r\n  <li>Complexity: Insertion of a single element into a hive takes constant\r\n    time and exactly one call to a constructor of <code>T</code>. Insertion of\r\n    multiple elements into a hive is linear in the number of elements\r\n    inserted, and the number of calls to the copy constructor or move\r\n    constructor of <code>T</code> is exactly equal to the number of elements\r\n    inserted.</li>\r\n  <li>Remarks: Does not affect the validity of iterators and references, unless\r\n    an iterator points to <code>end()</code>, in which case it may be\r\n    invalidated. Likewise if a reverse_iterator points to <code>rend()</code>\r\n    it may be invalidated. If an exception is thrown there are no effects.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">iterator erase(const_iterator position);</code>\r\n<ol start=\"3\">\r\n  <li>Effects: Invalidates only the iterators and references to the erased\r\n    element.</li>\r\n  <li>Complexity: Constant. [Note: operations pertaining to the updating of any data associated with the erased-elemment skipping mechanism is not factored into this; it is implementation-defined and may be constant, linear or otherwise defined. &mdash;end note]</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">iterator erase(const_iterator first, const_iterator last);</code>\r\n<ol start=\"5\">\r\n  <li>Effects: Invalidates only the iterators and references to the erased\r\n    elements. In some cases if an iterator is equal to <code>end()</code> and\r\n    the back element of the hive is erased, that iterator may be invalidated.\r\n    Likewise if a reverse_iterator is equal to <code>rend()</code> and the\r\n    front element of the hive is erased, that reverse_iterator may be\r\n    invalidated.</li>\r\n  <li>Complexity: Linear in the number of elements erased for\r\n    non-trivially-destructible types, for trivially-destructible types constant\r\n    in best case and linear in worst case, approximating logarithmic in the\r\n    number of elements erased on average.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">void swap(hive&amp; x) noexcept(allocator_traits&lt;Allocator&gt;::propagate_on_container_swap::value || allocator_traits&lt;Allocator&gt;::is_always_equal::value);<br>\r\n</code>\r\n<ol start=\"7\">\r\n  <li>Effects: Exchanges the contents and <code>capacity()</code> of\r\n    <code>*this</code> with that of <code>x</code>.</li>\r\n  <li>Complexity: Constant time.</li>\r\n</ol>\r\n\r\n\r\n<h4>22.3.14.5 Operations [hive.operations]</h4>\r\n\r\n<code style=\"font-weight:bold\">void splice(hive &amp;x);</code>\r\n<ol>\r\n  <li>Preconditions: &amp;x != this.</li>\r\n  <li>Effects: Inserts the contents of <code>x</code> into <code>*this</code>\r\n    and <code>x</code> becomes empty. Pointers and references to the moved\r\n    elements of <code>x</code> now refer to those same elements but as members\r\n    of <code>*this</code>. Iterators referring to the moved elements will\r\n    continue to refer to their elements, but they now behave as iterators into\r\n    <code>*this</code>, not into <code>x</code>.</li>\r\n  <li>Complexity: Constant time.</li>\r\n  <li>Throws: <code>length_error</code> if any of <code>x</code>'s element memory block capacities are outside the current minimum and maximum element\r\n    memory block capacity limits of <code>*this</code>.<sup><a href=\"#r223\">223</a></sup></li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">std::hive_limits block_capacity_limits() const noexcept;</code>\r\n<ol start=\"4\">\r\n  <li>Effects: Returns a std::hive_limits struct with the <code>min</code> and\r\n    <code>max</code> members set to the current minimum and maximum element\r\n    memory block capacity limits of <code>*this</code>.</li>\r\n  <li>Complexity: Constant time.</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">void reshape(std::hive_limits block_capacity_limits);</code><br>\r\n<ol start=\"6\">\r\n  <li>Preconditions: <code>T</code> shall be <i>Cpp17MoveInsertable</i> into\r\n    <code>*this</code>.<br>\r\n  </li>\r\n  <li>Effects: Sets minimum and maximum element memory block capacities to the\r\n    min and max members of the supplied std::hive_limits struct. If the hive is\r\n    not empty, adjusts existing memory block capacities to conform to the new\r\n    minimum and maximum block capacities, where necessary. If existing memory\r\n    block capacities are within the supplied minimum/maximum range, no\r\n    reallocation of elements takes place. If they are not within the supplied\r\n    range, elements are reallocated to new memory blocks which fit within the\r\n    supplied range and the old memory blocks are deallocated. Order of elements\r\n    is not guaranteed to be stable.</li>\r\n  <li>Complexity: If no reallocation occurs, constant time. If reallocation\r\n    occurs, complexity is linear in the number of elements reallocated.</li>\r\n  <li>Throws: <code>length_error</code> if <code>block_capacities.min</code> or\r\n    <code>block_capacities.max</code> are outside the implementation's minimum\r\n    and maximum element memory block capacity limits, or if\r\n    <code>block_capacities.min &gt; block_capacities.max</code>.<sup><a href=\"#r223\">223</a></sup></li>\r\n  <li>Remarks: The order of elements post-operation is not guaranteed to be\r\n    stable (16.5.5.8).</li>\r\n</ol>\r\n<br>\r\n\r\n<code style=\"font-weight:bold\">iterator get_iterator(pointer p) noexcept;<br>\r\nconst_iterator get_iterator(const_pointer p) const noexcept;</code>\r\n<ol start=\"11\">\r\n  <li>Effects: Returns an iterator or const_iterator pointing to the same element as the\r\n    pointer or const_pointer. If <code>p</code> does not point to an element in\r\n    <code>*this</code>, <code>end()</code> is returned.</li>\r\n</ol>\r\n<br>\r\n\r\n<pre><code style=\"font-weight:bold\">void sort();\r\ntemplate &lt;class Compare&gt;\r\n  void sort(Compare comp);</code></pre>\r\n<ol start=\"12\">\r\n  <li>Preconditions: <code>T</code> is <i>Cpp17MoveInsertable</i> into\r\n    <code>*this</code>.</li>\r\n  <li>Effects: Sorts the hive according to the <code>operator &lt;</code> or\r\n    a <code>Compare</code> function object. If an exception is thrown, the\r\n    order of the elements in <code>*this</code> is unspecified. Iterators and\r\n    references may be invalidated.</li>\r\n  <li>Complexity: Approximately N log N comparisons, where <code>N == size()</code>.</li>\r\n  <li>Throws: <code>bad_alloc</code> if it fails to allocate any memory necessary for the sort process.</li>\r\n  <li>Remarks: Not required to be stable (16.5.5.8). May allocate memory.</li>\r\n</ol>\r\n\r\n\r\n\r\n<h4>22.3.14.6 Specialized algorithms [hive.special]</h4>\r\n<pre><code style=\"font-weight:bold\">friend void swap(hive &amp;x, hive &amp;y) noexcept(noexcept(x.swap(y)));</code></pre>\r\n<ol>\r\n  <li>Effects: As if by <code>x.swap(y)</code>.</li>\r\n  <li>Remarks: This function is to be found via argument-dependent\r\nlookup only.</li>\r\n</ol>\r\n<br>\r\n\r\n<pre><code style=\"font-weight:bold\">friend bool operator== (const hive &amp;x, const hive &amp;y);\r\nfriend bool operator!= (const hive &amp;x, const hive &amp;y);</code></pre>\r\n<ol start=\"3\">\r\n  <li>Returns: For ==, returns <code>True</code> if both containers have the same elements in the same iterative sequence, otherwise <code>False</code>.\r\n  For !=, returns <code>True</code> if both containers do not have the same elements in the same iterative sequence, otherwise <code>False</code>.</li>\r\n  <li>Remarks: These functions are to be found via argument-dependent lookup only.</li>\r\n</ol>\r\n\r\n\r\n\r\n<pre><code style=\"font-weight:bold\">\r\nclass iterator\r\n{\r\n  friend void advance(iterator &amp;it, Distance n);\r\n  friend iterator next(iterator it, difference_type distance = 1);\r\n  friend iterator prev(iterator it, difference_type distance = 1);\r\n  friend difference_type distance(iterator first, iterator last);\r\n}\r\n\r\n\r\nclass const_iterator\r\n{\r\n  friend void advance(const_iterator &amp;it, Distance n);\r\n  friend const_iterator next(const_iterator it, difference_type distance = 1);\r\n  friend const_iterator prev(const_iterator it, difference_type distance = 1);\r\n  friend difference_type distance(const_iterator first, const_iterator last);\r\n}\r\n\r\n\r\nclass reverse_iterator\r\n{\r\n  friend void advance(reverse_iterator &amp;it, Distance n);\r\n  friend reverse_iterator next(reverse_iterator it, difference_type distance = 1);\r\n  friend reverse_iterator prev(reverse_iterator it, difference_type distance = 1);\r\n  friend difference_type distance(reverse_iterator first, reverse_iterator last);\r\n}\r\n\r\n\r\nclass const_reverse_iterator\r\n{\r\n  friend void advance(const_reverse_iterator &amp;it, Distance n);\r\n  friend const_reverse_iterator next(const_reverse_iterator it, difference_type distance = 1);\r\n  friend const_reverse_iterator prev(const_reverse_iterator it, difference_type distance = 1);\r\n  friend difference_type distance(const_reverse_iterator first, const_reverse_iterator last);\r\n}\r\n</code></pre>\r\n<ol start=\"5\">\r\n<li>Complexity: Constant in best case and linear in the number of elements traversed in worst case, approximating logarithmic in the number of elements traversed on average.</li>\r\n  <li>Remarks: These functions are to be found via argument-dependent lookup only.</li>\r\n</ol>\r\n<br>\r\n\r\n\r\n<h4>22.3.14.7 Erasure [hive.erasure]</h4>\r\n\r\n<pre><code style=\"font-weight:bold\">template &lt;class U&gt;\r\n    friend size_type erase(hive&amp; c, const U&amp; value);</code></pre>\r\n<ol>\r\n  <li>Effects: All elements in the container which are equal to <code>value</code> are erased. Invalidates all references and iterators to the erased elements.</li>\r\n  <li>Remarks: This function is to be found via argument-dependent lookup only.</li>\r\n</ol>\r\n<br>\r\n\r\n<pre><code style=\"font-weight:bold\">template &lt;class Predicate&gt;\r\n    friend size_type erase_if(hive&amp; c, Predicate pred);</code></pre>\r\n<ol start=\"3\">\r\n  <li>Effects: All elements in the container which match predicate <code>pred</code> are erased. Invalidates all references and iterators to the erased elements.</li>\r\n  <li>Remarks: This function is to be found via argument-dependent lookup only.</li>\r\n</ol>\r\n\r\n\r\n<h2><a id=\"acknowledgements\"></a>VII. Acknowledgements</h2>\r\n\r\n<p>Matt would like to thank: Glen Fernandes and Ion Gaztanaga for restructuring\r\nadvice, Robert Ramey for documentation advice, various Boost and SG14 members for support, critiques and corrections, Baptiste Wicht for teaching me how to construct decent benchmarks, Jonathan Wakely, Sean Middleditch, Jens Maurer (very nearly a co-author at this point really),\r\nPatrice Roy and Guy Davidson for standards-compliance advice and critiques, support, representation at meetings and bug reports, Henry Miller for getting me to clarify why the instrusive list/free list approach to memory location reuse is the most appropriate, Ville Voutilainen and Gasper Azman for help with the colony/hive rename paper, that ex-Lionhead guy for annoying me enough to force me to implement the original skipfield pattern, Jon Blow for some initial advice and Mike Acton for some influence, the community at large for giving me feedback and bug reports on the reference implementation.<br>\r\nAlso Nico Josuttis for doing such a great job in terms of explaining the general format of the structure to the committee.</p>\r\n\r\n\r\n<h2>VIII. Appendices</h2>\r\n\r\n<h3><a id=\"basicusage\"></a>Appendix A - Basic usage examples</h3>\r\n\r\n<p>Using <a href=\"https://plflib.org/colony.htm\">reference implementation</a>.</p>\r\n\r\n<div\r\nstyle=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\">\r\n<pre style=\"margin: 0; line-height: 125%\"><code><span style=\"color: #557799\">#include &lt;iostream&gt;</span>\r\n<span style=\"color: #557799\">#include &lt;numeric&gt;</span>\r\n<span style=\"color: #557799\">#include \"plf_hive.h\"</span>\r\n\r\n<span style=\"color: #333399; font-weight: bold\">int</span> <span style=\"color: #0066BB; font-weight: bold\">main</span>(<span style=\"color: #333399; font-weight: bold\">int</span> argc, <span style=\"color: #333399; font-weight: bold\">char</span> <span style=\"color: #333333\">**</span>argv)\r\n{\r\n  plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span><span style=\"color: #333333\">&gt;</span> i_hive;\r\n\r\n  <span style=\"color: #888888\">// Insert 100 ints:</span>\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (<span style=\"color: #333399; font-weight: bold\">int</span> i <span style=\"color: #333333\">=</span> <span style=\"color: #0000DD; font-weight: bold\">0</span>; i <span style=\"color: #333333\">!=</span> <span style=\"color: #0000DD; font-weight: bold\">100</span>; <span style=\"color: #333333\">++</span>i)\r\n  {\r\n    i_hive.insert(i);\r\n  }\r\n\r\n  <span style=\"color: #888888\">// Erase half of them:</span>\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span><span style=\"color: #333333\">&gt;::</span>iterator it <span style=\"color: #333333\">=</span> i_hive.begin(); it <span style=\"color: #333333\">!=</span> i_hive.end(); <span style=\"color: #333333\">++</span>it)\r\n  {\r\n    it <span style=\"color: #333333\">=</span> i_hive.erase(it);\r\n  }\r\n\r\n  std<span style=\"color: #333333\">::</span>cout <span style=\"color: #333333\">&lt;&lt;</span> <span style=\"background-color: #fff0f0\">\"Total: \"</span> <span style=\"color: #333333\">&lt;&lt;</span> std::accumulate(i_hive.begin(), i_hive.end(), 0) <span style=\"color: #333333\">&lt;&lt;</span> std<span style=\"color: #333333\">::</span>endl;\r\n  std<span style=\"color: #333333\">::</span>cin.get();\r\n  <span style=\"color: #008800; font-weight: bold\">return</span> <span style=\"color: #0000DD; font-weight: bold\">0</span>;\r\n} </code></pre>\r\n</div>\r\n\r\n<h4>Example demonstrating pointer stability</h4>\r\n\r\n<div\r\nstyle=\"background: #ffffff; overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;\">\r\n<pre style=\"margin: 0; line-height: 125%\"><code><span style=\"color: #557799\">#include &lt;iostream&gt;</span>\r\n<span style=\"color: #557799\">#include \"plf_hive.h\"</span>\r\n\r\n<span style=\"color: #333399; font-weight: bold\">int</span> <span style=\"color: #0066BB; font-weight: bold\">main</span>(<span style=\"color: #333399; font-weight: bold\">int</span> argc, <span style=\"color: #333399; font-weight: bold\">char</span> <span style=\"color: #333333\">**</span>argv)\r\n{\r\n  plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span><span style=\"color: #333333\">&gt;</span> i_hive;\r\n  plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span><span style=\"color: #333333\">&gt;::</span>iterator it;\r\n  plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span> <span style=\"color: #333333\">*&gt;</span> p_hive;\r\n  plf<span style=\"color: #333333\">::</span>hive<span style=\"color: #333333\">&lt;</span><span style=\"color: #333399; font-weight: bold\">int</span> <span style=\"color: #333333\">*&gt;::</span>iterator p_it;\r\n\r\n  <span style=\"color: #888888\">// Insert 100 ints to i_hive and pointers to those ints to p_hive:</span>\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (<span style=\"color: #333399; font-weight: bold\">int</span> i <span style=\"color: #333333\">=</span> <span style=\"color: #0000DD; font-weight: bold\">0</span>; i <span style=\"color: #333333\">!=</span> <span style=\"color: #0000DD; font-weight: bold\">100</span>; <span style=\"color: #333333\">++</span>i)\r\n  {\r\n    it <span style=\"color: #333333\">=</span> i_hive.insert(i);\r\n    p_hive.insert(<span style=\"color: #333333\">&amp;</span>(<span style=\"color: #333333\">*</span>it));\r\n  }\r\n\r\n  <span style=\"color: #888888\">// Erase half of the ints:</span>\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (it <span style=\"color: #333333\">=</span> i_hive.begin(); it <span style=\"color: #333333\">!=</span> i_hive.end(); <span style=\"color: #333333\">++</span>it)\r\n  {\r\n    it <span style=\"color: #333333\">=</span> i_hive.erase(it);\r\n  }\r\n\r\n  <span style=\"color: #888888\">// Erase half of the int pointers:</span>\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (p_it <span style=\"color: #333333\">=</span> p_hive.begin(); p_it <span style=\"color: #333333\">!=</span> p_hive.end(); <span style=\"color: #333333\">++</span>p_it)\r\n  {\r\n    p_it <span style=\"color: #333333\">=</span> p_hive.erase(p_it);\r\n  }\r\n\r\n  <span style=\"color: #888888\">// Total the remaining ints via the pointer hive (pointers will still be valid even after insertions and erasures):</span>\r\n  <span style=\"color: #333399; font-weight: bold\">int</span> total <span style=\"color: #333333\">=</span> <span style=\"color: #0000DD; font-weight: bold\">0</span>;\r\n\r\n  <span style=\"color: #008800; font-weight: bold\">for</span> (p_it <span style=\"color: #333333\">=</span> p_hive.begin(); p_it <span style=\"color: #333333\">!=</span> p_hive.end(); <span style=\"color: #333333\">++</span>p_it)\r\n  {\r\n    total <span style=\"color: #333333\">+=</span> <span style=\"color: #333333\">*</span>(<span style=\"color: #333333\">*</span>p_it);\r\n  }\r\n\r\n  std<span style=\"color: #333333\">::</span>cout <span style=\"color: #333333\">&lt;&lt;</span> <span style=\"background-color: #fff0f0\">\"Total: \"</span> <span style=\"color: #333333\">&lt;&lt;</span> total <span style=\"color: #333333\">&lt;&lt;</span> std<span style=\"color: #333333\">::</span>endl;\r\n\r\n  <span style=\"color: #008800; font-weight: bold\">if</span> (total <span style=\"color: #333333\">==</span> <span style=\"color: #0000DD; font-weight: bold\">2500</span>)\r\n  {\r\n    std<span style=\"color: #333333\">::</span>cout <span style=\"color: #333333\">&lt;&lt;</span> <span style=\"background-color: #fff0f0\">\"Pointers still valid!\"</span> <span style=\"color: #333333\">&lt;&lt;</span> std<span style=\"color: #333333\">::</span>endl;\r\n  }\r\n\r\n  std<span style=\"color: #333333\">::</span>cin.get();\r\n  <span style=\"color: #008800; font-weight: bold\">return</span> <span style=\"color: #0000DD; font-weight: bold\">0</span>;\r\n} </code></pre>\r\n</div>\r\n\r\n<h3><a id=\"benchmarks\"></a>Appendix B - Reference implementation benchmarks</h3>\r\n\r\n<p>Benchmark results for the hive reference implementation under GCC on an Intel Xeon E3-1241 (Haswell) are <a\r\nhref=\"https://plflib.org/benchmarks_haswell_gcc.htm\">here</a>.</p>\r\n\r\n<p>Old benchmark results for an earlier version of hive under MSVC 2015\r\nupdate 3, on an Intel Xeon E3-1241 (Haswell) are <a\r\nhref=\"https://plflib.org/benchmarks_haswell_msvc.htm\">here</a>. There is no\r\ncommentary for the MSVC results.</p>\r\n\r\n<h3><a id=\"faq\"></a>Appendix C - Frequently Asked Questions</h3>\r\n<ol>\r\n  <li><h4>Where is it worth using a hive in place of other std::\r\n    containers?</h4>\r\n    <p>As mentioned, it is worthwhile for performance reasons in situations\r\n    where the order of container elements is not important and:</p>\r\n    <ol type=\"a\">\r\n      <li>Insertion order is unimportant</li>\r\n      <li>Insertions and erasures to the container occur frequently in\r\n        performance-critical code, <i><b>and</b></i> </li>\r\n      <li>Links to non-erased container elements may not be invalidated by\r\n        insertion or erasure.</li>\r\n    </ol>\r\n    <p>Under these circumstances a hive will generally out-perform other\r\n    std:: containers. In addition, because it never invalidates pointer\r\n    references to container elements (except when the element being pointed to\r\n    has been previously erased) it may make many programming tasks involving\r\n    inter-relating structures in an object-oriented or modular environment much\r\n    faster, and could be considered in those circumstances.</p>\r\n  </li>\r\n  <li><h4>What are some examples of situations where a hive might improve\r\n    performance?</h4>\r\n    <p>Some ideal situations to use a hive: cellular/atomic simulation,\r\n    persistent octtrees/quadtrees, game entities or destructible-objects in a\r\n    video game, particle physics, anywhere where objects are being created and\r\n    destroyed continuously. Also, anywhere where a vector of pointers to\r\n    dynamically-allocated objects or a std::list would typically end up being\r\n    used in order to preserve pointer stability but where order is\r\n    unimportant.</p>\r\n  </li>\r\n  <li><h4>Is it similar to a deque?</h4>\r\n    <p>A deque is reasonably dissimilar to a hive - being a double-ended\r\n    queue, it requires a different internal framework. In addition, being a\r\n    random-access container, having a growth factor for memory blocks in a\r\n    deque is problematic (though not impossible). A deque and hive have no\r\n    comparable performance characteristics except for insertion (assuming a\r\n    good deque implementation). Deque erasure performance varies wildly\r\n    depending on the implementation, but is generally similar to vector erasure\r\n    performance. A deque invalidates pointers to subsequent container elements\r\n    when erasing elements, which a hive does not, and guarantees ordered\r\n    insertion.</p>\r\n  </li>\r\n  <li><h4>What are the thread-safe guarantees?</h4>\r\n    <p>Unlike a std::vector, a hive can be read from and inserted into at the\r\n    same time (assuming different locations for read and write), however it\r\n    cannot be iterated over and written to at the same time. If we look at a\r\n    (non-concurrent implementation of) std::vector's thread-safe matrix to see\r\n    which basic operations can occur at the same time, it reads as follows\r\n    (please note push_back() is the same as insertion in this regard):</p>\r\n\r\n    <table border=\"1\" cellspacing=\"3\">\r\n      <tbody>\r\n        <tr>\r\n          <td><b>std::vector</b></td>\r\n          <td>Insertion</td>\r\n          <td>Erasure</td>\r\n          <td>Iteration</td>\r\n          <td>Read</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Insertion</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Erasure</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Iteration</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>Yes</td>\r\n          <td>Yes</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Read</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>Yes</td>\r\n          <td>Yes</td>\r\n        </tr>\r\n      </tbody>\r\n    </table>\r\n    <p>In other words, multiple reads and iterations over iterators can happen\r\n    simultaneously, but the potential reallocation and pointer/iterator\r\n    invalidation caused by insertion/push_back and erasure means those\r\n    operations cannot occur at the same time as anything else. </p>\r\n    <p>hive on the other hand does not invalidate pointers/iterators to\r\n    non-erased elements during insertion and erasure, resulting in the\r\n    following matrix:</p>\r\n\r\n    <table border=\"1\" cellspacing=\"3\">\r\n      <tbody>\r\n        <tr>\r\n          <td><b>hive</b></td>\r\n          <td>Insertion</td>\r\n          <td>Erasure</td>\r\n          <td>Iteration</td>\r\n          <td>Read</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Insertion</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>Yes</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Erasure</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>Mostly*</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Iteration</td>\r\n          <td>No</td>\r\n          <td>No</td>\r\n          <td>Yes</td>\r\n          <td>Yes</td>\r\n        </tr>\r\n        <tr>\r\n          <td>Read</td>\r\n          <td>Yes</td>\r\n          <td>Mostly*</td>\r\n          <td>Yes</td>\r\n          <td>Yes</td>\r\n        </tr>\r\n      </tbody>\r\n    </table>\r\n    <p><span style=\"font-size: 10pt\">* Erasures will not invalidate iterators\r\n    unless the iterator points to the erased element.</span></p>\r\n    <p>In other words, reads may occur at the same time as insertions and\r\n    erasures (provided that the element being erased is not the element being\r\n    read), multiple reads and iterations may occur at the same time, but\r\n    iterations may not occur at the same time as an erasure or insertion, as\r\n    either of these may change the state of the skipfield which is being\r\n    iterated over, if a skipfield is used in the implementation. Note that iterators pointing to end() may be invalidated by\r\n    insertion.</p>\r\n    <p>So, hive could be considered more inherently thread-safe than a\r\n    (non-concurrent implementation of) std::vector, but still has some areas\r\n    which would require mutexes or atomics to navigate in a multithreaded\r\n    environment.</p>\r\n  </li>\r\n  <li><h4>Any pitfalls to watch out for?</h4>\r\n    <p>Because erased-element memory locations may be reused by\r\n    <code>insert()</code> and <code>emplace()</code>, insertion position is\r\n    essentially random unless no erasures have been made, or an equal number of\r\n    erasures and insertions have been made.</p>\r\n  </li>\r\n  <li><h4>What is the purpose of limiting memory block minimum and maximum\r\n    sizes?</h4>\r\n    <p>One reason might be to ensure that memory blocks match a certain\r\n    processor's cache or memory pathway sizes. Another reason to do this is\r\n    that it is slightly slower to obtain an erased-element location from the\r\n    list of groups-with-erasures (subsequently utilising that group's free list\r\n    of erased locations) and to reuse that space than to insert a new element\r\n    to the back of the hive (the default behavior when there are no\r\n    previously-erased elements). If there are any erased elements in active memory blocks at the moment of insertion, hive will recycle those memory locations.</p>\r\n    <p>So if a block size is large, and many erasures occur but the block is\r\n    not completely emptied, iterative performance might suffer due to large\r\n    memory gaps between any two non-erased elements and subsequent drop in data\r\n    locality and cache performance. In that scenario you may want to experiment\r\n    with benchmarking and limiting the minimum/maximum sizes of the blocks,\r\n    such that memory blocks are freed earlier and find the optimal size for the\r\n    given use case.</p>\r\n  </li>\r\n  <li><h4>What is hive's Abstract Data Type (ADT)?</h4>\r\n    <p>Though I am happy to be proven wrong I suspect hives/colonies/bucket arrays\r\n    are their own abstract data type. Some have suggested it's ADT is of type\r\n    bag, I would somewhat dispute this as it does not have typical bag\r\n    functionality such as <a href=\"http://www.austincc.edu/akochis/cosc1320/bag.htm\">searching based on\r\n    value</a> (you can use std::find but it's o(n)) and adding this\r\n    functionality would slow down other performance characteristics. <a\r\n    href=\"https://en.wikipedia.org/wiki/Set_(abstract_data_type)#Multiset\">Multisets/bags</a>\r\n    are also not sortable (by means other than automatically by key value).\r\n    hive does not utilize key values, is sortable, and does not provide the\r\n    sort of functionality frequently associated with a bag (e.g. counting the\r\n    number of times a specific value occurs).</p>\r\n  </li>\r\n  <li><h4><a id=\"remove_when_empty\"></a>Why must blocks be removed from the iterative sequence when empty?</h4>\r\n    <p>Two reasons:</p>\r\n    <ol type=\"a\">\r\n      <li>Standards compliance: if blocks aren't removed then <code>++</code>\r\n        and <code>--</code> iterator operations become undefined in terms of\r\n        time complexity, making them non-compliant with the C++ standard. At\r\n        the moment they are O(1) amortized, in the reference implementation this constitutes typically one update for both\r\n        skipfield and element pointers, but two if a skipfield jump takes the\r\n        iterator beyond the bounds of the current block and into the next\r\n        block. But if empty blocks are allowed, there could be anywhere between\r\n        1 and <code>std::numeric_limits&lt;size_type&gt;::max</code> empty\r\n        blocks between the current element and the next. Essentially you get\r\n        the same scenario as you do when iterating over a boolean skipfield. It\r\n        would be possible to move these to the back of the hive as trailing\r\n        blocks, or house them in a separate list or vector for future usage,\r\n        but this may create performance issues if any of the blocks are not at\r\n        their maximum size (see below).</li>\r\n      <li>Performance: iterating over empty blocks is slower than them not\r\n        being present, of course - but also if you have to allow for empty\r\n        blocks while iterating, then you have to include a while loop in every\r\n        iteration operation, which increases cache misses and code size. The\r\n        strategy of removing blocks when they become empty also statistically\r\n        removes (assuming randomized erasure patterns) smaller blocks from the\r\n        hive before larger blocks, which has a net result of improving\r\n        iteration, because with a larger block, more iterations within the\r\n        block can occur before the end-of-block condition is reached and a jump\r\n        to the next block (and subsequent cache miss) occurs. Lastly, pushing\r\n        to the back of a hive, provided there is still space and no new block\r\n        needs to be allocated, will be faster than recycling memory locations\r\n        as each subsequent insertion occurs in a subsequent memory location\r\n        (which is cache-friendlier) and also less computational work is\r\n        necessary. If a block is removed from the iterative sequence its recyclable memory locations are\r\n        also not usable, hence subsequent insertions are more likely to\r\n        be pushed to the back of the hive.</li>\r\n    </ol>\r\n  </li>\r\n  <li><h4>Why not reserve all empty memory blocks for future use during erasure, or None, rather than leaving this decision\r\n    undefined by the specification?</h4>\r\n    <p>The default scenario, for reasons of predictability, should be to free\r\n    the memory block in most cases. However for the reasons described in the design decisions section on erase(), retaining the back block at least has performance and latency benefits.\r\n    Therefore retaining no memory blocks is non-optimal in cases where the user is not using a custom allocator. Meanwhile, retaining All memory blocks is bad for performance as many small memory blocks will be retained, which decreases iterative performance due to lower cache locality.\r\n    However, one perspective is that if a scenario calls for\r\n    retaining memory blocks instead of deallocating them, this should be left\r\n    to an allocator to manage. Otherwise you get unpredictable memory behavior\r\n    across implementations, and this is one of the things that SG14 members\r\n    have complained about consistently with STL implementations. This is currently an open topic for discussion.</p>\r\n  </li>\r\n  <li><h4>Memory block sizes - what are they based on, how do they expand,\r\n    etc</h4>\r\n    <p>While implementations are free to chose their own limits and strategies here,\r\n\t in the reference implementation memory block sizes start from either the\r\n    dynamically-defined default minimum size (8 elements, larger if the type stored is small) or an\r\n    amount defined by the end user (with a minimum of 3 elements, as there is enough metadata per-block that less than 3 elements is generally a waste of memory unless the value_type is extremely large).\r\n\t Subsequent block sizes then increase the <i>total capacity</i> of the hive by a\r\n    factor of 2 (so, 1st block 8 elements, 2nd 8 elements, 3rd 16 elements, 4th\r\n    32 elements etcetera) until the maximum block size is reached. The default\r\n    maximum block size in the reference implementation is the maximum possible number that the skipfield\r\n    bitdepth is capable of representing (std::numeric_limits&lt;skipfield_type&gt;::max()). By default the\r\n    skipfield bitdepth is 16 so the maximum size of a block would be 65535\r\n    elements in that context.</p>\r\n    <p>The skipfield bitdepth was initially a template parameter which could be set to\r\n    any unsigned integer - unsigned char, unsigned int, Uint_64, etc. Unsigned\r\n    short (guaranteed to be at least 16 bit, equivalent to C++11's\r\n    uint_least16_t type) was found to have the best performance in real-world\r\n    testing on x86 and x86_64 platforms due to the balance between memory contiguousness, memory waste and\r\n    the number of allocations. unsigned char was found to have better performance below 1000 elements and of course lower memory use. Other platforms have not been tested. Since only two values were considered useful, they've been replaced in newer versions by a <code>priority</code> parameter, which specifies whether the priority of the instantiation is memory use or performance. While this is not strictly true in the sense that unsigned char will also have better performance for under 1000 elements, it is a compromise in order to have the implementation reflect a standard which may enable other implementations which do not share the same performance characteristics.</p>\r\n  </li>\r\n  <li><h4><a id=\"simd\"></a>Can a hive be used with SIMD instructions?</h4>\r\n    <p>No and yes. Yes if you're careful, no if you're not.<br>\r\n    On platforms which support scatter and gather operations via hardware (e.g.\r\n    AVX512) you can use hive with SIMD as much as you want, using gather to\r\n    load elements from disparate or sequential locations, directly into a SIMD\r\n    register, in parallel. Then use scatter to push the post-SIMD-process\r\n    values elsewhere after. On platforms which do not support this in hardware,\r\n    you would need to manually implement a scalar gather-and-scatter operation\r\n    which may be significantly slower.</p>\r\n    <p>In situations where gather and scatter operations are too expensive,\r\n    which require elements to be contiguous in memory for SIMD processing, this\r\n    is more complicated. When you have a bunch of erasures in a hive, there's\r\n    no guarantee that your objects will be contiguous in memory, even though\r\n    they are sequential during iteration. Some of them may also be in different\r\n    memory blocks to each other. In these situations if you want to use SIMD\r\n    with hive, you must do the following:</p>\r\n    <ul>\r\n      <li>Set your minimum and maximum group sizes to multiples of the width of\r\n        your target processor's SIMD instruction size. If it supports 8\r\n        elements at once, set the group sizes to multiples of 8.</li>\r\n      <li>Either never erase from the hive, or:<br>\r\n        <ol>\r\n          <li>Shrink-to-fit after you erase (will invalidate all pointers to\r\n            elements within the hive).</li>\r\n          <li>Only erase from the back or front of the hive, and only erase\r\n            elements in multiples of the width of your SIMD instruction e.g. 8\r\n            consecutive elements at once. This will ensure that the\r\n            end-of-memory-block boundaries line up with the width of the SIMD\r\n            instruction, provided you've set your min/max block sizes as\r\n          above.</li>\r\n        </ol>\r\n      </li>\r\n    </ul>\r\n    <p>Generally if you want to use SIMD without gather/scatter, it's probably\r\n    preferable to use a vector or an array.</p>\r\n  </li>\r\n</ol>\r\n\r\n<h3><a id=\"responses\" name=\"responses\"></a>Appendix D - Specific responses to\r\nprevious committee feedback</h3>\r\n<ol>\r\n  <li><h4>Naming</h4>\r\n    <p>See D2332R0.</p>\r\n  </li>\r\n  <li><h4>\"Unordered and no associative lookup, so this only supports use cases\r\n    where you're going to do something to every element.\"</h4>\r\n    <p>As noted the container was originally designed for highly\r\n    object-oriented situations where you have many elements in different\r\n    containers linking to many other elements in other containers. This linking\r\n    can be done with pointers or iterators in hive (insert returns an\r\n    iterator which can be dereferenced to get a pointer, pointers can be\r\n    converted into iterators with the supplied functions (for erase etc)) and\r\n    because pointers/iterators stay stable regardless of insertion/erasure,\r\n    this usage is unproblematic. You could say the pointer is equivalent to a\r\n    key in this case (but without the overhead). That is the first access\r\n    pattern, the second is straight iteration over the container, as you say.\r\n    Secondly, the container does have (typically better than O(n))\r\n    advance/next/prev implementations, so multiple elements can be skipped.</p>\r\n  </li>\r\n  <li><h4>\"Do we really need the Priority template parameter?\"</h4>\r\n    <p>While technically a non-binding request, this parameter promotes the use of the container in heavily\r\n    memory-constrained environments like embedded programming. In the context of the reference implementation this means switching the skipfield type from unsigned short to unsigned char, in other implementations it could mean something else.\r\n\t See more explanation in V. Technical Specifications.\r\n    Unfortunately this parameter also means <code>operator=</code>, swap and some\r\n    other functions won't work between hives of the same type but with differing priorities.</p>\r\n  </li>\r\n  <li><h4>\"Prove this is not an allocator\"</h4>\r\n    <p>I'm not really sure how to answer this, as I don't see the resemblance,\r\n    unless you count maps, vectors etc as being allocators also. The only\r\n    aspect of it which resembles what an allocator might do, is the memory\r\n    re-use mechanism. It would be impossible for an allocator to perform a\r\n    similar function while still allowing the container to iterate over the\r\n    data linearly in memory, preserving locality, in the manner described in\r\n    this document.</p>\r\n  </li>\r\n  <li><h4>\"If this is for games, won't game devs just write their own versions\r\n    for specific types in order to get a 1% speed increase anyway?\"</h4>\r\n    <p>This is true for many/most AAA game companies who are on the bleeding\r\n    edge, but they also do this for vector etc, so they aren't the target\r\n    audience of std:: for the most part; sub-AAA game companies are more likely\r\n    to use third party/pre-existing tools. As mentioned earlier, this structure\r\n    (bucket-array-like) crops up in <a\r\n    href=\"https://groups.google.com/a/isocpp.org/forum/#!topic/sg14/1iWHyVnsLBQ\">many,\r\n    many fields</a>, not just game dev. So the target audience is probably\r\n    everyone other than AAA gaming, but even then, it facilitates communication\r\n    across fields and companies as to this type of container, giving it a\r\n    standardized name and understanding.</p>\r\n  </li>\r\n  <li><h4>\"Is there active research in this problem space? Is it likely to\r\n    change in future?\"</h4>\r\n    <p>The only current analysis has been around the question of whether it's\r\n    possible for this specification to fail to allow for a better\r\n    implementation in future. This is unlikely given the container's\r\n    requirements and how this impacts on implementation. Bucket arrays have\r\n    been around since the 1990s, there's been no significant innovation in them\r\n    until now. I've been researching/working on hive since early 2015, and\r\n    while I can't say for sure that a better implementation might not be\r\n    possible, I am confident that no change should be necessary to the\r\n    specification to allow for future implementations, if it is done correctly.\r\n    </p>\r\n    <p>The requirement of allowing no reallocations upon insertion or erasure,\r\n    truncates possible implementation strategies significantly. Memory blocks\r\n    have to be independently allocated so that they can be removed (when empty)\r\n    without triggering reallocation of subsequent elements. There's limited\r\n    numbers of ways to do that and keep track of the memory blocks at the same\r\n    time. Erased element locations must be recorded (for future re-use by\r\n    insertion) in a way that doesn't create allocations upon erasure, and\r\n    there's limited numbers of ways to do this also. Multiple consecutive\r\n    erased elements have to be skipped in O(1) time, and again there's limits\r\n    to how many ways you can do that. That covers the three core aspects upon\r\n    which this specification is based. See <a href=\"#design\"></a>IV. Design\r\n    Decisions for the various ways these aspects can be designed.</p>\r\n    <p>The time complexity of updates to whatever erased-element skipping mechanism is used should, I think, be left\r\n    implementation-defined, as defining time complexity may obviate better\r\n    solutions which are faster but are not necessarily O(1). These updates\r\n    would likely occur during erasure, insertion, splicing and container copying.</p>\r\n  </li>\r\n  <li><h4>Why not iterate across the memory blocks backwards to find the first block with erasures to reuse, during insert?</h4>\r\n  <p>While this would statistically ensure that smaller blocks get deallocated first due to becoming empty faster than later blocks, it introduces uncertain latency issues during insert, particularly when custom memory block sizes are used and the number of elements is large. With the current implementation there is an intrusive list of blocks with erasures, and within each block's metadata there's a free list of skipblocks. When reusing the current head of the intrusive list determines the block, and the current head of that block's free list determines the skipblock to be reused. This means that the most recently erased element will be the first to reused. This works out well for two reasons: currently-contiguous sequences of elements will tend to stay that way, helping cache coherence, and when elements are erased and inserted in sequence those erased memory locations will tend to be already in the cache when inserting. Lastly, this structure involves a minimum of branching and checks, resulting in minimal latency during insertion and erasure.</p>\r\n</ol>\r\n\r\n<h3><a id=\"sg14gameengine\"></a>Appendix E - Typical game engine\r\nrequirements</h3>\r\n\r\n<p>Here are some more specific requirements with regards to game engines,\r\nverified by game developers within SG14:</p>\r\n<ol type=\"a\">\r\n  <li>Elements within data collections refer to elements within other data\r\n    collections (through a variety of methods - indices, pointers, etc). These\r\n    references must stay valid throughout the course of the game/level. Any\r\n    container which causes pointer or index invalidation creates difficulties\r\n    or necessitates workarounds.</li>\r\n  <li>Order is unimportant for the most part. The majority of data is simply\r\n    iterated over, transformed, referred to and utilized with no regard to\r\n    order.</li>\r\n  <li>Erasing or otherwise \"deactivating\" objects occurs frequently in\r\n    performance-critical code. For this reason methods of erasure which create\r\n    strong performance penalties are avoided.</li>\r\n  <li>Inserting new objects in performance-critical code (during gameplay) is\r\n    also common - for example, a tree drops leaves, or a player spawns in an\r\n    online multiplayer game.</li>\r\n  <li>It is not always clear in advance how many elements there will be in a\r\n    container at the beginning of development, or at the beginning of a level\r\n    during play. Genericized game engines in particular have to adapt to\r\n    considerably different user requirements and scopes. For this reason\r\n    extensible containers which can expand and contract in realtime are\r\n    necessary.</li>\r\n  <li>Due to the effects of cache on performance, memory storage which is\r\n    more-or-less contiguous is preferred.</li>\r\n  <li>Memory waste is avoided.</li>\r\n</ol>\r\n\r\n<p>std::vector in its default state does not meet these requirements due to:\r\n</p>\r\n<ol>\r\n  <li>Poor (non-fill) single insertion performance (regardless of insertion\r\n    position) due to the need for reallocation upon reaching capacity</li>\r\n  <li>Insert invalidates pointers/iterators to all elements </li>\r\n  <li>Erase invalidates pointers/iterators/indexes to all elements after the\r\n    erased element</li>\r\n</ol>\r\n\r\n<p>Game developers therefore either develop custom solutions for each scenario\r\nor implement workarounds for vector. The most common workarounds are most\r\nlikely the following or derivatives:</p>\r\n<ol>\r\n  <li>Using a boolean flag or similar to indicate the inactivity of an object\r\n    (as opposed to actually erasing from the vector). Elements flagged as\r\n    inactive are skipped during iteration.<br>\r\n    <br>\r\n    Advantages: Fast \"deactivation\". Easy to manage in multi-access\r\n    environments.<br>\r\n    Disadvantages: Can be slower to iterate due to branching.</li>\r\n  <li>Using a vector of data and a secondary vector of indexes. When erasing,\r\n    the erasure occurs only in the vector of indexes, not the vector of data.\r\n    When iterating it iterates over the vector of indexes and accesses the data\r\n    from the vector of data via the remaining indexes.<br>\r\n    <br>\r\n    Advantages: Fast iteration.<br>\r\n    Disadvantages: Erasure still incurs some reallocation cost which can\r\n    increase jitter.</li>\r\n  <li>Combining a swap-with-back-element-and-pop approach to erasure with some form of\r\n    dereferenced lookup system to enable contiguous element iteration\r\n    (sometimes called a 'packed array': <a href=\"http://bitsquid.blogspot.ca/2011/09/managing-decoupling-part-4-id-lookup.html\">http://bitsquid.blogspot.ca/2011/09/managing-decoupling-part-4-id-lookup.html</a>).\r\n    <br>\r\n    Advantages: Iteration is at standard vector speed.<br>\r\n    Disadvantages: Erasure will be slow if objects are large and/or\r\n    non-trivially copyable, thereby making swap costs large. All link-based\r\n    access to elements incur additional costs due to the dereferencing system.\r\n  </li>\r\n</ol>\r\n\r\n<p>hive brings a more generic solution to these contexts. While some\r\ndevelopers, particularly AAA developers, will almost always develop a custom\r\nsolution for specific use-cases within their engine, I believe most sub-AAA and\r\nindie developers are more likely to rely on third party solutions. Regardless,\r\nstandardising the container will allow for greater cross-discipline\r\ncommunication.</p>\r\n\r\n<h3><a id=\"timecomplexityexplanations\"></a>Appendix F - Time complexity\r\nrequirement explanations</h3>\r\n\r\n<h5>Insert (single): O(1)</h5>\r\n\r\n<p>One of the requirements of hive is that pointers to non-erased elements\r\nstay valid regardless of insertion/erasure within the container. For this\r\nreason the container must use multiple memory blocks. If a single memory block\r\nwere used, like in a std::vector, reallocation of elements would occur when the\r\ncontainer expanded (and the elements were copied to a larger memory block).\r\nInstead, hive will insert into existing memory blocks when able, and create a\r\nnew memory block when all existing memory blocks are full. This keeps insertion\r\nat O(1).</p>\r\n\r\n<h5>Insert (multiple): O(N)</h5>\r\n\r\n<p>Multiple insertions may allow an implementation to reserve suitably-sized\r\nmemory blocks in advance, reducing the number of allocations necessary (whereas\r\nsingular insertion would generally follow the implementation's block growth\r\npattern, possibly allocating more than necessary). However when it comes to\r\ntime complexity it has no advantages over singular insertion, is linear to the\r\nnumber elements inserted.</p>\r\n\r\n<h5>Erase (single): O(1)</h5>\r\n\r\n<p>Erasure is a simple matter of destructing the element in question and\r\nupdating whatever data is associated with the erased-element skipping mechanism eg. the skipfield. Since we use a skipping mechanism to avoid erasures during\r\niterator, no reallocation of subsequent elements is necessary and the process\r\nis O(1). Additionally, when using a Low-complexity jump-counting pattern the\r\nskipfield update is also always O(1).</p>\r\n\r\n<p>Note: When a memory block becomes empty of non-erased elements it must be\r\nfreed to the OS (or reserved for future insertions, depending on implementation)\r\nand removed from the hive's sequence of memory blocks. It it was not, we\r\nwould end up with non-O(1) iteration, since there would be no way to predict\r\nhow many empty memory blocks there would be between the current memory block\r\nbeing iterated over, and the next memory block with non-erased (active)\r\nelements in it.</p>\r\n\r\n\r\n<h5>Erase (multiple): O(N) for non-trivially-destructible types, for\r\ntrivially-destructible types between O(1) and O(N) depending on range\r\nstart/end, approximating O(log n) average</h5>\r\n\r\n<p>In this case, where the element is non-trivially destructible, the time\r\ncomplexity is O(N), with infrequent deallocation necessary from the removal of\r\nan empty memory block as noted above. However where the elements are\r\ntrivially-destructible, if the range spans an entire memory block at any point,\r\nthat block and it's metadata can simply be removed without doing any\r\nindividual writes to it's metadata or individual destruction of elements,\r\npotentially making this a O(1) operation.</p>\r\n\r\n<p>In addition (when dealing with trivially-destructible types) for those\r\nmemory blocks where only a portion of elements are erased by the range, if no\r\nprior erasures have occurred in that memory block you may be able to erase that range in\r\nO(1) time, as, for example, if you are using a skipfield there will be no need to check the skipfield within the range for\r\npreviously erased elements. The reason you would need to check for previously\r\nerased elements within that portion's range is so you can update the metadata\r\nfor that memory block to accurately reflect how many non-erased elements remain\r\nwithin the block. The non-erased element-count metadata is necessary because\r\nthere is no other way to ascertain when a memory block is empty of non-erased\r\nelements, and hence needs to be removed from the hive's iteration sequence.\r\nThe reasoning for why empty memory blocks must be removed is included in the\r\nErase(single) section, above.</p>\r\n\r\n<p>However in most cases the erase range will not perfectly match the size of\r\nall memory blocks, and with typical usage of a hive there is usually some\r\nprior erasures in most memory blocks. So, for example, when dealing with a\r\nhive of a trivially-destructible type, you might end up with a tail portion\r\nof the first memory block in the erasure range being erased in O(N) time, the\r\nsecond and intermediary memory block being completely erased and freed in O(1)\r\ntime, and only a small front portion of the third and final memory block in the\r\nrange being erased in O(N) time. Hence the time complexity for\r\ntrivially-destructible elements approximates O(log n) on average, being between\r\nO(1) and O(N) depending on the start and end of the erasure range.</p>\r\n\r\n\r\n<h5>std::find: O(N)</h5>\r\n\r\n<p>This relies on basic iteration so is O(N).</p>\r\n\r\n\r\n<h5>splice: O(1)</h5>\r\n\r\n<p>hive only does full-container splicing, not partial-container splicing\r\n(use range-insert with std::make_move_iterator to achieve the latter, albiet\r\nwith the loss of pointer validity to the moved range). When splicing, the\r\nmemory blocks from the source hive are transferred to the destination hive\r\nwithout processing the individual elements. These blocks may either be placed\r\nat the front of the hive or the end, depending on how full the source back\r\nblock is compared to the destination back block. If the destination back block\r\nis more full ie. there is less unused space in it, it is better to put it at\r\nthe beginning of the source block - as otherwise this creates a larger gap to\r\nskip during iteration which in turn affects cache locality. If there are unused\r\nelement memory spaces at the back of the destination container (ie. the final\r\nmemory block is not full) and a skipfield is used, the skipfield nodes corresponding to those empty\r\nspaces must be altered to indicate that these are skipped elements.</p>\r\n\r\n\r\n<h5>Iterator operators ++ and --: O(1) amortized</h5>\r\n\r\n<p>Generally the time complexity is O(1), and if a skipfield pattern is used it must\r\nallow for O(1) skipping of multiple erased elements. However every so often\r\niteration will involve a transistion to the next/previous memory block in the\r\nhive's sequence of blocks, depending on whether we are doing ++ or --. At\r\nthis point a read of the next/previous memory block's corresponding skipfield would be\r\nnecessary, in case the front/back element(s) in that memory block are erased\r\nand hence skipped. So for every block transition, 2 reads of the skipfield are\r\nnecessary instead of 1. Hence the time complexity is O(1) amortized.</p>\r\n\r\n<p>If skipfields are used they must be per-element-memory-block and independent of subsequent/previous memory blocks, as\r\notherwise you end up with a vector for a skipfield, which would need a\r\nrange erased every time a memory block was removed from the hive (see notes\r\nunder Erase, above), and reallocation to a larger skipfield memory block when a\r\nhive expanded. Both of these procedures carry reallocation costs, meaning you\r\ncould have thousands of skipfield nodes needing to be reallocated based on a\r\nsingle erasure (from within a memory block which only had one non-erased\r\nelement left and hence would need to be removed from the hive). This is\r\nunacceptable latency for any field involving high timing sensitivity (all of <a\r\nhref=\"https://lists.isocpp.org/mailman/listinfo.cgi/sg14/\">SG14</a>).</p>\r\n\r\n\r\n<h5>begin()/end(): O(1)</h5>\r\n\r\n<p>For any implementation these should generally be stored as member variables\r\nand so returning them is O(1).</p>\r\n\r\n\r\n<h5>advance/next/prev: between O(1) and O(n), depending on current iterator\r\nlocation, distance and implementation. Average for reference implementation\r\napproximates O(log N).</h5>\r\n\r\n<p>The reasoning for this is similar to that of Erase(multiple), above.\r\nComplexity is dependent on state of hive, position of iterator and length of\r\n<code>distance</code>, but in many cases will be less than linear. It is\r\nnecessary in a hive to store metadata both about the capacity of each block\r\n(for the purpose of iteration) and how many non-erased elements are present\r\nwithin the block (for the purpose of removing blocks from the iterative chain\r\nonce they become empty). For this reason, intermediary blocks between the\r\niterator's initial block and its final destination block (if these are not the\r\nsame block, and if the initial block and final block are not immediately\r\nadjacent) can be skipped rather than iterated linearly across, by subtracting\r\nthe \"number of non-erased elements\" metadata from <code>distance</code> for\r\nthose blocks.</p>\r\n\r\n<p>This means that the only linear time operations are any iterations within\r\nthe initial block and the final block. However if either the initial or final\r\nblock have no erased elements (as determined by comparing whether the block's\r\ncapacity metadata and the block's \"number of non-erased elements\" metadata are\r\nequal), linear iteration can be skipped for that block and pointer/index math\r\nused instead to determine distances, reducing complexity to constant time.\r\nHence the best case for this operation is constant time, the worst is linear to\r\nthe distance.</p>\r\n\r\n\r\n<h5>distance: between O(1) and O(n), depending on current iterator location,\r\ndistance and implementation. Average for reference implementation approximates\r\nO(log N).</h5>\r\n\r\n<p>The same considerations which apply to advance, prev and next also apply to\r\ndistance - intermediary blocks between iterator1 and iterator2's blocks can be\r\nskipped in constant time, if they exist. iterator1's block and iterator2's\r\nblock (if these are not the same block) must be linearly iterated across using\r\n++ unless either block has no erased elements, in which case the operation\r\nbecomes pointer/index math and is reduced to constant time for that block. In\r\naddition, if iterator1's block is not the same as iterator2's block, and\r\niterator2 is equal to end() or (end() - 1), or is the last element in that\r\nblock, iterator2's block's elements can also counted from the metadata rather\r\nthan iteration.</p>\r\n\r\n\r\n<h3><a id=\"yunoconstexpr\"></a>Appendix G - Why not constexpr?</h3>\r\n<p>I am somewhat awkwardly forced into a position where I have to question and push back against the currently-unsubstantiated enthusiasm around constexpr containers and functions. At the time of writing there are no compilers which both support constexpr non-trivial destructors and also have a working implementation of a constexpr container. And until that is remedied, we won't really know what we're dealing with. My own testing in terms of making hive constexpr has not been encouraging. 2% performance decrease in un-altered benchmark code is common, and I suspect the common cause of this is caching values from compile-time when it is cheaper to calculate them on-the-fly than to return them from main memory. This suspicion is based on the substantial increases in executable size in the constexpr versions.</p>\r\n\r\n<p>For an example of the latter, think about size() in std::vector. This can be calculated in most implementations by (vector.end_iterator.pointer - vector.memory_block), both of which will most likely be in cache at the time of calling size(). That's if size isn't a member variable or something.\r\nCalculating a minus operation on stuff that's already in cache is about 100x faster than making a call out to main memory for a compile-time-stored value of this function, if that is necessary. Hence calculating size() will typically be faster than storing it, but a constexpr implementation and compiler currently won't make that distinction.</p>\r\n\r\n<p>None of which is an issue if a container is being entirely used within a constexpr function which has been determined to be evaluated at compile time. The problems occur when constexpr containers are used in runtime code, but certain functions such as size() are determined to be able to be evaluated at compile time, and therefore have their results cached. This is not an okay situation. If there were a mechanism which specified that for a given class instance, it's constexpr functions may <b>not</b> be evaluated at compile time, then I would give the go-ahead. Similarly if there were a rule which stated that a class instance's member functions may only be evaluated at compile time if the class instance is instantiated and destructed at compile time, I would give the go-ahead. This is not the situation we have, and I can't support it.</p>\r\n\r\n<p>Constexpr function calls:</p>\r\n<ol type=\"a\">\r\n<li>shift the responsibility of storage of pre-calculated results from the programmer to the compiler, and remove the ability for the programmer to think about the cache locality/optimal storage of precalculated results</li>\r\n<li>shift the decision of whether or not to evaluate at runtime/compile-time to the compiler, where in some cases doing it at compile-time and storing the result may decrease performance (see the <a href=\"https://fabiensanglard.net/doom3_documentation/DOOM-3-BFG-Technical-Note.pdf\">Doom 3 BFG edition technical notes</a> for their experience with pre-calc'ing meshes vs calculating them on the fly)</li>\r\n<li>may dramatically increase code size/file size in some cases if the return results of constexpr functions are large</li>\r\n<li>may dramatically increase compile times</li>\r\n<li>create the potential for cache pollution when constexpr functions return large amounts of data, or when functions returning small amounts of data are called many times</li>\r\n</ol>\r\n\r\n<p>Given this, and the performance issues mentioned above, I am reluctant to make hive constexpr-by-default. Time may sort these issues out, but I am personally happier for std::array and std::vector to be the \"canaries in the coalmine\" here. Certainly I won't be giving the go-ahead on any change that produces, or can produce, on current compilers, a 2% performance decrease in runtime code. Though I acknowledge the functionality of constexpr code may be useful to many.</p>\r\n\r\n\r\n<h3><a id=\"referencediff\"></a>Appendix H - Reference implementation differences and link</h3>\r\n<p>The <a href=\"https://plflib.org/colony.htm\">reference implementation</a> has a couple of key differences from the proposal, one is that it is named 'colony' by default, for historical and userbase reasons, and typedef'd to hive for optional usage under that name. This is only possible with C++11 and above due to the limits on template typedefs under C++98/03. Likewise the template parameter 'hive_priority' is a regular enum in the reference implementation, instead of a scoped enum, in order to be usable with C++98/03, and is 'colony_priority' by default with a typedef to hive_priority. Lastly the struct 'colony_limits' is also typedef'd to 'hive_limits'. Otherwise the reference implementation is or should be identical with the std::hive proposal.</p>\r\n\r\n\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "Docs/Proposals/Fixed_Point_Library_Proposal.md",
    "content": "**Document number**: LEWG, EWG, SG14, SG6: P0037R0  \n**Date**: 2015-09-28  \n**Project**: Programming Language C++, Library Evolution WG, SG14  \n**Reply-to**: John McFarlane, [fixed-point@john.mcfarlane.name](mailto:fixed-point@john.mcfarlane.name)\n\n# Fixed-Point Real Numbers\n\n## I. Introduction\n\nThis proposal introduces a system for performing binary fixed-point\narithmetic using built-in integral types.\n\n## II. Motivation\n\nFloating-point types are an exceedingly versatile and widely supported\nmethod of expressing real numbers on modern architectures.\n\nHowever, there are certain situations where fixed-point arithmetic is\npreferable. Some systems lack native floating-point registers and must\nemulate them in software. Many others are capable of performing some\nor all operations more efficiently using integer arithmetic. Certain\napplications can suffer from the variability in precision which comes\nfrom a dynamic radix point [\\[1\\]](http://www.pathengine.com/Contents/Overview/FundamentalConcepts/WhyIntegerCoordinates/page.php).\nIn situations where a variable exponent is not desired, it takes\nvaluable space away from the significand and reduces precision.\n\nBuilt-in integer types provide the basis for an efficient\nrepresentation of binary fixed-point real numbers. However, laborious,\nerror-prone steps are required to normalize the results of certain\noperations and to convert to and from fixed-point types.\n\nA set of tools for defining and manipulating fixed-point types is\nproposed. These tools are designed to make work easier for those who\ntraditionally use integers to perform low-level, high-performance\nfixed-point computation.\n\n## III. Impact On the Standard\n\nThis proposal is a pure library extension. It does not require\nchanges to any standard classes, functions or headers.\n\n## IV. Design Decisions\n\nThe design is driven by the following aims in roughly descending\norder:\n\n1. to automate the task of using integer types to perform low-level\n   binary fixed-point arithmetic;\n2. to facilitate a style of code that is intuitive to anyone who is\n   comfortable with integer and floating-point arithmetic;\n3. to avoid type promotion, implicit conversion or other behavior that\n   might lead to surprising results and\n4. to preserve significant digits at the expense of insignificant\n   digits, i.e. to prefer underflow to overflow.\n\n### Class Template\n\nFixed-point numbers are specializations of\n\n    template <class ReprType, int Exponent>\n    class fixed_point;\n\nwhere the template parameters are described as follows.\n\n#### `ReprType` Type Template Parameter\n\nThis parameter identifies the capacity and signedness of the\nunderlying type used to represent the value. In other words, the size\nof the resulting type will be `sizeof(ReprType)` and it will be\nsigned iff `is_signed<ReprType>::value` is true. The default is\n`int`.\n\n`ReprType` must be a fundamental integral type and should not be the\nlargest size. Suitable types include: `std::int8_t`, `std::uint8_t`,\n`std::int16_t`, `std::uint16_t`, `std::int32_t` and `std::uint32_t`.\nIn limited situations, `std::int64_t` and `std::uint64_t` can be used.\nThe  reasons for these limitations relate to the difficulty in finding\na type that is suitable for performing lossless integer\nmultiplication.\n\n#### `Exponent` Non-Type Template Parameter\n\nThe exponent of a fixed-point type is the equivalent of the exponent\nfield in a floating-point type and shifts the stored value by the\nrequisite number of bits necessary to produce the desired range. The\ndefault value of `Exponent` is zero, giving `fixed_point<T>` the same\nrange as `T`.\n\nThe resolution of a specialization of `fixed_point` is\n\n    pow(2, Exponent)\n\nand the minimum and maximum values are\n\n    std::numeric_limits<ReprType>::min() * pow(2, Exponent)\n\nand\n\n    std::numeric_limits<ReprType>::max() * pow(2, Exponent)\n\nrespectively.\n\nAny usage that results in values of `Exponent` which lie outside the\nrange, (`INT_MIN / 2`, `INT_MAX / 2`), may result in undefined\nbehavior and/or overflow or underflow. This range of exponent values\nis far in excess of the largest built-in floting-point type and should\nbe adequate for all intents and purposes.\n\n### `make_fixed` and `make_ufixed` Helper Type\n\nThe `Exponent` template parameter is versatile and concise. It is an\nintuitive scale to use when considering the full range of positive and\nnegative exponents a fixed-point type might possess. It also\ncorresponds to the exponent field of built-in floating-point types.\n\nHowever, most fixed-point formats can be described more intuitively by\nthe cardinal number of integer and/or fractional digits they contain.\nMost users will prefer to distinguish fixed-point types using these\nparameters.\n\nFor this reason, two aliases are defined in the style of\n`make_signed`.\n\nThese aliases are declared as:\n\n    template <unsigned IntegerDigits, unsigned FractionalDigits = 0, bool IsSigned = true>\n  \tusing make_fixed;\n\nand\n\n    template <unsigned IntegerDigits, unsigned FractionalDigits = 0>\n    using make_ufixed;\n\nThey resolve to a `fixed_point` specialization with the given\nsignedness and number of integer and fractional digits. They may\ncontain additional integer and fractional digits.\n\nFor example, one could define and initialize an 8-bit, unsigned,\nfixed-point variable with four integer digits and four fractional\ndigits:\n\n    make_ufixed<4, 4> value { 15.9375 };\n\nor a 32-bit, signed, fixed-point number with two integer digits and 29\nfractional digits:\n\n    make_fixed<2, 29> value { 3.141592653 };\n\n### Conversion\n\nFixed-point numbers can be explicitly converted to and from built-in\narithmetic types.\n\nWhile effort is made to ensure that significant digits are not lost\nduring conversion, no effort is made to avoid rounding errors.\nWhatever would happen when converting to and from an integer type\nlargely applies to `fixed_point` objects also. For example:\n\n    make_ufixed<4, 4>(.006) == make_ufixed<4, 4>(0)\n\n...equates to `true` and is considered a acceptable rounding error.\n\n### Operator Overloads\n\nAny operators that might be applied to integer types can also be\napplied to fixed-point types. A guiding principle of operator\noverloads is that they perform as little run-time computation as is\npractically possible.\n\nWith the exception of shift and comparison operators, binary operators\ncan take any combination of:\n\n* one or two fixed-point arguments and\n* zero or one arguments of any arithmetic type, i.e. a type for which\n  `is_arithmetic` is true.\n\nWhere the inputs are not identical fixed-point types, a simple set of\npromotion-like rules are applied to determine the return type:\n\n1. If both arguments are fixed-point, a type is chosen which is the\n   size of the larger type, is signed if either input is signed and\n   has the maximum integer bits of the two inputs, i.e. cannot lose\n   high-significance bits through conversion alone.\n2. If one of the arguments is a floating-point type, then the type of\n   the result is the smallest floating-point type of equal or greater\n   size than the inputs.\n3. If one of the arguments is an integral type, then the result is the\n   other, fixed-point type.\n\nSome examples:\n\n    make_ufixed<5, 3>{8} + make_ufixed<4, 4>{3} == make_ufixed<5, 3>{11};  \n    make_ufixed<5, 3>{8} + 3 == make_ufixed<5, 3>{11};  \n    make_ufixed<5, 3>{8} + float{3} == float{11};  \n\nThe reasoning behind this choice is a combination of predictability\nand performance. It is explained for each rule as follows:\n\n1. ensures that the least computation is performed where fixed-point\n   types are used exclusively. Aside from multiplication and division\n   requiring shift operations, should require similar computational\n   costs to equivalent integer operations;\n2. loosely follows the promotion rules for mixed-mode arithmetic,\n   ensures values with exponents far beyond the range of the\n   fixed-point type are catered for and avoids costly conversion from\n   floating-point to integer and\n3. preserves the input fixed-point type whose range is far more likely\n   to be of deliberate importance to the operation.\n\nShift operator overloads require an integer type as the right-hand\nparameter and return a type which is adjusted to accommodate the new\nvalue without risk of overflow or underflow.\n\nComparison operators convert the inputs to a common result type\nfollowing the rules above before performing a comparison and returning\n`true` or `false`.\n\n#### Overflow\n\nBecause arithmetic operators return a result of equal capacity to\ntheir inputs, they carry a risk of overflow. For instance,\n\n    make_fixed<4, 3>(15) + make_fixed<4, 3>(1)\n\ncauses overflow because because a type with 4 integer bits cannot\nstore a value of 16.\n\nOverflow of any bits in a signed or unsigned fixed-point type is\nclassed as undefined behavior. This is a minor deviation from\nbuilt-in integer arithmetic where only signed overflow results in\nundefined behavior.\n\n#### Underflow\n\nThe other typical cause of lost bits is underflow where, for example,\n\n    make_fixed<7, 0>(15) / make_fixed<7, 0>(2)\n\nresults in a value of 7. This results in loss of precision but is\ngenerally considered acceptable.\n\nHowever, when all bits are lost due to underflow, the value is said\nto be flushed and this is classed as undefined behavior.\n\n### Dealing With Overflow and Flushes\n\nErrors resulting from overflow and flushes are two of the biggest\nheadaches related to fixed-point arithmetic. Integers suffer the same\nkinds of errors but are somewhat easier to reason about as they lack\nfractional digits. Floating-point numbers are largely shielded from\nthese errors by their variable exponent and implicit bit.\n\nThree strategies for avoiding overflow in fixed-point types are\npresented:\n\n1. simply leave it to the user to avoid overflow;\n2. promote the result to a larger type to ensure sufficient capacity\n   or\n3. adjust the exponent of the result upward to ensure that the top\n   limit of the type is sufficient to preserve the most significant\n   digits at the expense of the less significant digits.\n\nFor arithmetic operators, choice 1) is taken because it most closely\nfollows the behavior of integer types. Thus it should cause the least\nsurprise to the fewest users. This makes it far easier to reason\nabout in code where functions are written with a particular type in\nmind. It also requires the least computation in most cases.\n\nChoices 2) and 3) are more robust to overflow events. However, they\nrepresent different trade-offs and neither one is the best fit in all\nsituations. For these reasons, they are presented as named functions.\n\n#### Type Promotion\n\nFunction template, `promote`, borrows a term from the language\nfeature which avoids integer overflow prior to certain operations. It\ntakes a `fixed_point` object and returns the same value represented\nby a larger `fixed_point` specialization.\n\nFor example,\n\n    promote(make_fixed<5, 2>(15.5))\n\nis equivalent to\n\n    make_fixed<11, 4>(15.5)\n\nComplimentary function template, `demote`, reverses the process,\nreturning a value of a smaller type.\n\n#### Named Arithmetic Functions\n\nThe following named function templates can be used as a hassle-free\nalternative to arithmetic operators in situations where the aim is\nto avoid overflow.\n\nUnary functions:\n\n    trunc_reciprocal, trunc_square, trunc_sqrt,\n    promote_reciprocal, promote_square\n\nBinary functions:\n\n    trunc_add, trunc_subtract, trunc_multiply, trunc_divide\n    trunc_shift_left, trunc_shift_right,\n    promote_add, promote_sub, promote_multiply, promote_divide\n\nSome notes:\n\n1. The `trunc_` functions return the result as a type no larger than\n   the inputs and with an exponent adjusted to avoid overflow;\n2. the `promote_` functions return the result as a type large enough\n   to avoid overflow and underflow;\n3. the `_multiply` and `_square` functions are not guaranteed to be\n   available for 64-bit types;\n4. the `_multiply` and `_square` functions produce undefined behavior\n   when all input parameters are the *most negative number*;\n5. the `_square` functions return an unsigned type;\n6. the `_add`, `_subtract`, `_multiply` and `_divide` functions take\n   heterogeneous `fixed_point` specializations;\n7. the `_divide` and `_reciprocal` functions in no way guard against\n   divide-by-zero errors;\n8. the `trunc_shift_` functions return results of the same type as\n   their first input parameter and\n9. the list is by no means complete.\n\n### Example\n\nThe following example calculates the magnitude of a 3-dimensional vector.\n\n    template <class Fp>\n    constexpr auto magnitude(const Fp & x, const Fp & y, const Fp & z)\n    -> decltype(trunc_sqrt(trunc_add(trunc_square(x), trunc_square(y), trunc_square(z))))\n    {\n        return trunc_sqrt(trunc_add(trunc_square(x), trunc_square(y), trunc_square(z)));\n    }\n\nCalling the above function as follows\n\n    static_cast<double>(magnitude(\n        make_ufixed<4, 12>(1),\n        make_ufixed<4, 12>(4),\n        make_ufixed<4, 12>(9)));\n\nreturns the value, 9.890625.\n\n## V. Technical Specification\n\n### Header \\<fixed_point\\> Synopsis\n\n    namespace std {\n      template <class ReprType, int Exponent> class fixed_point;\n\n      template <unsigned IntegerDigits, unsigned FractionalDigits = 0, bool IsSigned = true>\n        using make_fixed;\n      template <unsigned IntegerDigits, unsigned FractionalDigits = 0>\n        using make_ufixed;\n      template <class ReprType, int IntegerDigits>\n        using make_fixed_from_repr;\n\n      template <class FixedPoint>\n        using promote_result;\n      template <class FixedPoint>\n        promote_result<FixedPoint>\n          constexpr promote(const FixedPoint & from) noexcept;\n\n      template <class FixedPoint>\n        using demote_result;\n      template <class FixedPoint>\n        demote_result<FixedPoint>\n          constexpr demote(const FixedPoint & from) noexcept;\n\n      template <class ReprType, int Exponent>\n      \tconstexpr bool operator==(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n        constexpr bool operator!=(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n          const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr bool operator<(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr bool operator>(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr bool operator>=(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr bool operator<=(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n\n      template <class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent> operator-(\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent> operator+(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent> operator-(\n      \t  const fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tfixed_point<ReprType, Exponent> & operator+=(\n      \t  fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tfixed_point<ReprType, Exponent> & operator-=(\n      \t  fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tfixed_point<ReprType, Exponent> & operator*=(\n      \t  fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tfixed_point<ReprType, Exponent> & operator/=(\n      \t  fixed_point<ReprType, Exponent> & lhs,\n      \t  const fixed_point<ReprType, Exponent> & rhs) noexcept;\n\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator==(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator!=(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator<(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator>(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator>=(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator<=(const Lhs & lhs, const Rhs & rhs) noexcept;\n\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator+(\n      \t  const Lhs & lhs,\n      \t  const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs>\n      \tconstexpr auto operator-(\n      \t  const Lhs & lhs,\n      \t  const Rhs & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator*(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator/(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class Integer>\n      \tconstexpr auto operator*(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const Integer & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class Integer>\n      \tconstexpr auto operator/(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const Integer & rhs) noexcept;\n      template <class Integer, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator*(\n      \t  const Integer & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class Integer, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator/(\n      \t  const Integer & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class Float>\n      \tconstexpr auto operator*(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const Float & rhs) noexcept;\n      template <class LhsReprType, int LhsExponent, class Float>\n      \tconstexpr auto operator/(\n      \t  const fixed_point<LhsReprType, LhsExponent> & lhs,\n      \t  const Float & rhs) noexcept;\n      template <class Float, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator*(\n      \t  const Float & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class Float, class RhsReprType, int RhsExponent>\n      \tconstexpr auto operator/(\n      \t  const Float & lhs,\n      \t  const fixed_point<RhsReprType, RhsExponent> & rhs) noexcept;\n      template <class LhsReprType, int Exponent, class Rhs>\n      \tfixed_point<LhsReprType, Exponent> & operator+=(fixed_point<LhsReprType, Exponent> & lhs, const Rhs & rhs) noexcept;\n      template <class LhsReprType, int Exponent, class Rhs>\n      \tfixed_point<LhsReprType, Exponent> & operator-=(fixed_point<LhsReprType, Exponent> & lhs, const Rhs & rhs) noexcept;\n      template <class LhsReprType, int Exponent>\n      template <class Rhs, typename std::enable_if<std::is_arithmetic<Rhs>::value, int>::type Dummy>\n      \tfixed_point<LhsReprType, Exponent> &\n      \tfixed_point<LhsReprType, Exponent>::operator*=(const Rhs & rhs) noexcept;\n      template <class LhsReprType, int Exponent>\n      template <class Rhs, typename std::enable_if<std::is_arithmetic<Rhs>::value, int>::type Dummy>\n      \tfixed_point<LhsReprType, Exponent> &\n      \tfixed_point<LhsReprType, Exponent>::operator/=(const Rhs & rhs) noexcept;\n      template <class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent>\n      \t  sqrt(const fixed_point<ReprType, Exponent> & x) noexcept;\n      template <class FixedPoint, unsigned N = 2>\n      \tusing trunc_add_result;\n\n      template <class FixedPoint, class ... Tail>\n      \ttrunc_add_result<FixedPoint, sizeof...(Tail) + 1>\n          constexpr trunc_add(const FixedPoint & addend1, const Tail & ... addend_tail);\n      template <class Lhs, class Rhs = Lhs>\n      \tusing trunc_subtract_result;\n      template <class Lhs, class Rhs>\n      \ttrunc_subtract_result<Lhs, Rhs>\n      \t  constexpr trunc_subtract(const Lhs & minuend, const Rhs & subtrahend);\n      template <class Lhs, class Rhs = Lhs>\n      \tusing trunc_multiply_result;\n\n      template <class Lhs, class Rhs>\n      \ttrunc_multiply_result<Lhs, Rhs>\n      \t  constexpr trunc_multiply(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class FixedPointDividend, class FixedPointDivisor = FixedPointDividend>\n      \tusing trunc_divide_result;\n      template <class FixedPointDividend, class FixedPointDivisor>\n      \ttrunc_divide_result<FixedPointDividend, FixedPointDivisor>\n      \t  constexpr trunc_divide(const FixedPointDividend & lhs, const FixedPointDivisor & rhs) noexcept;\n      template <class FixedPoint>\n      \tusing trunc_reciprocal_result;\n      template <class FixedPoint>\n      \ttrunc_reciprocal_result<FixedPoint>\n      \t  constexpr trunc_reciprocal(const FixedPoint & fixed_point) noexcept;\n      template <class FixedPoint>\n      \tusing trunc_square_result;\n\n      template <class FixedPoint>\n      \ttrunc_square_result<FixedPoint>\n      \t  constexpr trunc_square(const FixedPoint & root) noexcept;\n      template <class FixedPoint>\n      \tusing trunc_sqrt_result;\n      template <class FixedPoint>\n      \ttrunc_sqrt_result<FixedPoint>\n      \t  constexpr trunc_sqrt(const FixedPoint & square) noexcept;\n      template <int Integer, class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent + Integer>\n      \t  trunc_shift_left(const fixed_point<ReprType, Exponent> & fp) noexcept;\n      template <int Integer, class ReprType, int Exponent>\n      \tconstexpr fixed_point<ReprType, Exponent - Integer>\n      \t  trunc_shift_right(const fixed_point<ReprType, Exponent> & fp) noexcept;\n      template <class FixedPoint, unsigned N = 2>\n      \tusing promote_add_result;\n\n      template <class FixedPoint, class ... Tail>\n      \tpromote_add_result<FixedPoint, sizeof...(Tail) + 1>\n      \t  constexpr promote_add(const FixedPoint & addend1, const Tail & ... addend_tail);\n      template <class Lhs, class Rhs = Lhs>\n      \tusing promote_subtract_result\n      template <class Lhs, class Rhs>\n      \tpromote_subtract_result<Lhs, Rhs>\n      \t  constexpr promote_subtract(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs = Lhs>\n      \tusing promote_multiply_result;\n      template <class Lhs, class Rhs>\n      \tpromote_multiply_result<Lhs, Rhs>\n      \t  constexpr promote_multiply(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class Lhs, class Rhs = Lhs>\n      \tusing promote_divide_result;\n      template <class Lhs, class Rhs>\n      \tpromote_divide_result<Lhs, Rhs>\n      \t  constexpr promote_divide(const Lhs & lhs, const Rhs & rhs) noexcept;\n      template <class FixedPoint>\n      \tusing promote_square_result;\n      template <class FixedPoint>\n      \tpromote_square_result<FixedPoint>\n      \t  constexpr promote_square(const FixedPoint & root) noexcept;\n    }\n\n#### `fixed_point<>` Class Template\n\n    template <class ReprType = int, int Exponent = 0>\n    class fixed_point\n    {\n    public:\n      using repr_type = ReprType;\n\n      constexpr static int exponent;\n      constexpr static int digits;\n      constexpr static int integer_digits;\n      constexpr static int fractional_digits;\n\n      fixed_point() noexcept;\n      template <class S, typename std::enable_if<_impl::is_integral<S>::value, int>::type Dummy = 0>\n        explicit constexpr fixed_point(S s) noexcept;\n      template <class S, typename std::enable_if<std::is_floating_point<S>::value, int>::type Dummy = 0>\n        explicit constexpr fixed_point(S s) noexcept;\n      template <class FromReprType, int FromExponent>\n        explicit constexpr fixed_point(const fixed_point<FromReprType, FromExponent> & rhs) noexcept;\n      template <class S, typename std::enable_if<_impl::is_integral<S>::value, int>::type Dummy = 0>\n        fixed_point & operator=(S s) noexcept;\n      template <class S, typename std::enable_if<std::is_floating_point<S>::value, int>::type Dummy = 0>\n        fixed_point & operator=(S s) noexcept;\n      template <class FromReprType, int FromExponent>\n        fixed_point & operator=(const fixed_point<FromReprType, FromExponent> & rhs) noexcept;\n\n      template <class S, typename std::enable_if<_impl::is_integral<S>::value, int>::type Dummy = 0>\n        explicit constexpr operator S() const noexcept;\n      template <class S, typename std::enable_if<std::is_floating_point<S>::value, int>::type Dummy = 0>\n        explicit constexpr operator S() const noexcept;\n      explicit constexpr operator bool() const noexcept;\n\n      template <class Rhs, typename std::enable_if<std::is_arithmetic<Rhs>::value, int>::type Dummy = 0>\n        fixed_point &operator*=(const Rhs & rhs) noexcept;\n      template <class Rhs, typename std::enable_if<std::is_arithmetic<Rhs>::value, int>::type Dummy = 0>\n        fixed_point & operator/=(const Rhs & rhs) noexcept;\n\n      constexpr repr_type data() const noexcept;\n      static constexpr fixed_point from_data(repr_type repr) noexcept;\n    };\n\n## VI. Future Issues\n\n### Library Support\n\nBecause the aim is to provide an alternative to existing arithmetic\ntypes which are supported by the standard library, it is conceivable\nthat a future proposal might specialize existing class templates and\noverload existing functions.\n\nPossible candidates for overloading include the functions defined in\n\\<cmath\\> and a templated specialization of `numeric_limits`. A new type\ntrait, `is_fixed_point`, would also be useful.\n\nWhile `fixed_point` is intended to provide drop-in replacements to\nexisting built-ins, it may be preferable to deviate slightly from the\nbehavior of certain standard functions. For example, overloads of\nfunctions from \\<cmath\\> will be considerably less concise, efficient\nand versatile if they obey rules surrounding error cases. In\nparticular, the guarantee of setting `errno` in the case of an error\nprevents a function from being defined as pure. This highlights a\nwider issue surrounding the adoption of the functional approach and\ncompile-time computation that is beyond the scope of this document.\n\n### Alternatives to Built-in Integer Types\n\nThe reason that `ReprType` is restricted to built-in integer types\nis that a number of features require the use of a higher - or\nlower-capacity type. Supporting alias templates are defined to\nprovide `fixed_point` with the means to invoke integer types of\nspecific capacity and signedness at compile time.\n\nThere is no general purpose way of deducing a higher or\nlower-capacity type given a source type in the same manner as\n`make_signed` and `make_unsigned`. If there were, this might be\nadequate to allow alternative choices for `ReprType`.\n\n### Bounded Integers\n\nThe bounded::integer library [\\[2\\]](http://doublewise.net/c++/bounded/)\nexemplifies the benefits of keeping track of ranges of values in\narithmetic types at compile time.\n\nTo a limited extent, the `trunc_` functions defined here also keep\ntrack of - and modify - the limits of values. However, a combination\nof techniques is capable of producing superior results.\n\nFor instance, consider the following expression:\n\n    make_ufixed<2, 6> three(3);\n    auto n = trunc_square(trunc_square(three));\n\nThe type of `n` is `make_ufixed<8, 0>` but its value does not\nexceed 81. Hence, an integer bit has been wasted. It may be possible\nto track more accurate limits in the same manner as the\nbounded::integer library in order to improve the precision of types\nreturned by `trunc_` functions. For this reason, the exact value of\nthe exponents of these return types is not given.\n\nNotes:\n* Bounded::integer is already supported by fixed-point library,\nfp [\\[3\\]](https://github.com/mizvekov/fp).\n* A similar library is the boost constrained_value library\n[\\[4\\]](http://rk.hekko.pl/constrained_value/).\n\n### Alternative Policies\n\nThe behavior of the types specialized from `fixed_point` represent\none sub-set of all potentially desirable behaviors. Alternative\ncharacteristics include:\n\n* different rounding strategies - other than truncation;\n* overflow and underflow checks - possibly throwing exceptions;\n* operator return type - adopting `trunc_` or `promote_` behavior;\n* default-initialize to zero - currently uninitialized and\n* saturation arithmetic - as opposed to modular arithmetic.\n\nOne way to extend `fixed_point` to cover these alternatives would be\nto add non-type template parameters containing bit flags or enumerated\ntypes. The default set of values would reflect `fixed_point` as it\nstands currently.\n\n## VII. Prior Art\n\nMany examples of fixed-point support in C and C++ exist. While almost\nall of them aim for low run-time cost and expressive alternatives to\nraw integer manipulation, they vary greatly in detail and in terms of\ntheir interface.\n\nOne especially interesting dichotomy is between solutions which offer\na discrete selection of fixed-point types and libraries which contain\na continuous range of exponents through type parameterization.\n\n### N1169\n\nOne example of the former is found in proposal N1169\n[\\[5\\]](http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf),\nthe intent of which is to expose features found in certain embedded\nhardware. It introduces a succinct set of language-level fixed-point\ntypes and impose constraints on the number of integer or fractional\ndigits each can possess.\n\nAs with all examples of discrete-type fixed-point support, the limited\nchoice of exponents is a considerable restriction on the versatility\nand expressiveness of the API.\n\nNevertheless, it may be possible to harness performance gains provided\nby N1169 fixed-point types through explicit template specialization.\nThis is likely to be a valuable proposition to potential users of the\nlibrary who find themselves targeting platforms which support\nfixed-point arithmetic at the hardware level.\n\n### N3352\n\nThere are many other C++ libraries available which fall into the\nlatter category of continuous-range fixed-point arithmetic\n[\\[3\\]](https://github.com/mizvekov/fp)\n[\\[6\\]](http://www.codeproject.com/Articles/37636/Fixed-Point-Class)\n[\\[7\\]](https://github.com/viboes/fixed_point). In particular, an\nexisting library proposal, N3352 [\\[8\\]](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html),\naims to achieve very similar goals through similar means and warrants\ncloser comparison than N1169.\n\nN3352 introduces four class templates covering the quadrant of signed\nversus unsigned and fractional versus integer numeric types. It is\nintended to replace built-in types in a wide variety of situations and\naccordingly, is highly compile-time configurable in terms of how\nrounding and overflow are handled. Parameters to these four class\ntemplates include the storage in bits and - for fractional types - the\nresolution.\n\nThe `fixed_point` class template could probably - with a few caveats -\nbe generated using the two fractional types, `nonnegative` and\n`negatable`, replacing the `ReprType` parameter with the integer bit\ncount of `ReprType`, specifying `fastest` for the rounding mode and\nspecifying `undefined` as the overflow mode.\n\nHowever, fixed_point more closely and concisely caters to the needs of\nusers who already use integer types and simply desire a more concise,\nless error-prone form. It more closely follows the four design aims of\nthe library and - it can be argued - more closely follows the spirit\nof the standard in its pursuit of zero-cost abstraction.\n\nSome aspects of the design of the N3352 API which back up these\nconclusion are that:\n\n* the result of arithmetic operations closely resemble the `trunc_`\n  function templates and are potentially more costly at run-time;\n* the nature of the range-specifying template parameters - through\n  careful framing in mathematical terms - abstracts away valuable\n  information regarding machine-critical type size information;\n* the breaking up of duties amongst four separate class templates\n  introduces four new concepts and incurs additional mental load for\n  relatively little gain while further detaching the interface from\n  vital machine-level details and\n* the absence of the most negative number from signed types reduces\n  the capacity of all types by one.\n\nThe added versatility that the N3352 API provides regarding rounding\nand overflow handling are of relatively low priority to users who\nalready bear the scars of battles with raw integer types.\nNevertheless, providing them as options to be turned on or off at\ncompile time is an ideal way to leave the choice in the hands of the\nuser.\n\nMany high-performance applications - in which fixed-point is of\npotential value - favor run-time checks during development which are\nsubsequently deactivated in production builds. The N3352 interface is\nhighly conducive to this style of development. It is an aim of the\nfixed_point design to be similarly extensible in future revisions.\n\n## VIII. Acknowledgements\n\nSubgroup: Guy Davidson, Michael Wong  \nContributors: Ed Ainsley, Billy Baker, Lance Dyson, Marco Foco,\nClément Grégoire, Nicolas Guillemot, Matt Kinzelman, Joël Lamotte,\nSean Middleditch, Patrice Roy, Peter Schregle, Ryhor Spivak\n\n## IX. References\n\n1. Why Integer Coordinates?, <http://www.pathengine.com/Contents/Overview/FundamentalConcepts/WhyIntegerCoordinates/page.php>\n2. C++ bounded::integer library, <http://doublewise.net/c++/bounded/>\n3. fp, C++14 Fixed Point Library, <https://github.com/mizvekov/fp>\n4. Boost Constrained Value Libarary, <http://rk.hekko.pl/constrained_value/>\n5. N1169, Extensions to support embedded processors, <http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf>\n6. fpmath, Fixed Point Math Library, <http://www.codeproject.com/Articles/37636/Fixed-Point-Class>\n7. Boost fixed_point (proposed), Fixed point integral and fractional types, <https://github.com/viboes/fixed_point>\n8. N3352, C++ Binary Fixed-Point Arithmetic, <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html>\n9. fixed_point, Reference Implementation of P0037, <https://github.com/johnmcfarlane/fixed_point>\n\n## X. Appendix 1: Reference Implementation\n\nAn in-development implementation of the fixed_point class template and\nits essential supporting functions and types is available\n[\\[9\\]](https://github.com/johnmcfarlane/fixed_point). It includes a\nutility header containing such things as math and trigonometric\nfunctions and a partial `numeric_limits` specialization. Compile-time\nand run-time tests are included as well as benchmarking support. It is\nthe source of examples and measurements cited here.\n\n## XI. Appendix 2: Performance\n\nDespite a focus on usable interface and direct translation from\ninteger-based fixed-point operations, there is an overwhelming\nexpectation that the source code result in minimal instructions and\nclock cycles. A few preliminary numbers are presented to give a very\nearly idea of how the API might perform.\n\nSome notes:\n\n* A few test functions were run, ranging from single arithmetic\n  operations to basic geometric functions, performed against integer,\n  floating-point and fixed-point types for comparison.\n* Figures were taken from a single CPU, OS and compiler, namely:\n\n      Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)\n      Target: x86_64-pc-linux-gnu\n      Thread model: posix\n\n* Fixed inputs were provided to each function, meaning that branch\n  prediction rarely fails. Results may also not represent the full\n  range of inputs.\n* Details of the test harness used can be found in the source\n  project mentioned in Appendix 1;\n* Times are in nanoseconds;\n* Code has not yet been optimized for performance.\n\n### Types\n\nWhere applicable various combinations of integer, floating-point and\nfixed-point types were tested with the following identifiers:\n\n* `uint8_t`, `int8_t`, `uint16_t`, `int16_t`, `uint32_t`, `int32_t`,\n  `uint64_t` and `int64_t` built-in integer types;\n* `float`, `double` and `long double` built-in floating-point types;\n* s3:4, u4:4, s7:8, u8:8, s15:16, u16:16, s31:32 and u32:32 format\n  fixed-point types.\n\n### Basic Arithmetic\n\nPlus, minus, multiplication and division were tested in isolation\nusing a number of different numeric types with the following results:\n\nname\tcpu_time  \nadd(float)\t1.78011  \nadd(double)\t1.73966  \nadd(long double)\t3.46011  \nadd(u4_4)\t1.87726  \nadd(s3_4)\t1.85051  \nadd(u8_8)\t1.85417  \nadd(s7_8)\t1.82057  \nadd(u16_16)\t1.94194  \nadd(s15_16)\t1.93463  \nadd(u32_32)\t1.94674  \nadd(s31_32)\t1.94446  \nadd(int8_t)\t2.14857  \nadd(uint8_t)\t2.12571  \nadd(int16_t)\t1.9936  \nadd(uint16_t)\t1.88229  \nadd(int32_t)\t1.82126  \nadd(uint32_t)\t1.76  \nadd(int64_t)\t1.76  \nadd(uint64_t)\t1.83223  \nsub(float)\t1.96617  \nsub(double)\t1.98491  \nsub(long double)\t3.55474  \nsub(u4_4)\t1.77006  \nsub(s3_4)\t1.72983  \nsub(u8_8)\t1.72983  \nsub(s7_8)\t1.72983  \nsub(u16_16)\t1.73966  \nsub(s15_16)\t1.85051  \nsub(u32_32)\t1.88229  \nsub(s31_32)\t1.87063  \nsub(int8_t)\t1.76  \nsub(uint8_t)\t1.74994  \nsub(int16_t)\t1.82126  \nsub(uint16_t)\t1.83794  \nsub(int32_t)\t1.89074  \nsub(uint32_t)\t1.85417  \nsub(int64_t)\t1.83703  \nsub(uint64_t)\t2.04914  \nmul(float)\t1.9376  \nmul(double)\t1.93097  \nmul(long double)\t102.446  \nmul(u4_4)\t2.46583  \nmul(s3_4)\t2.09189  \nmul(u8_8)\t2.08  \nmul(s7_8)\t2.18697  \nmul(u16_16)\t2.12571  \nmul(s15_16)\t2.10789  \nmul(u32_32)\t2.10789  \nmul(s31_32)\t2.10789  \nmul(int8_t)\t1.76  \nmul(uint8_t)\t1.78011  \nmul(int16_t)\t1.8432  \nmul(uint16_t)\t1.76914  \nmul(int32_t)\t1.78011  \nmul(uint32_t)\t2.19086  \nmul(int64_t)\t1.7696  \nmul(uint64_t)\t1.79017  \ndiv(float)\t5.12  \ndiv(double)\t7.64343  \ndiv(long double)\t8.304  \ndiv(u4_4)\t3.82171  \ndiv(s3_4)\t3.82171  \ndiv(u8_8)\t3.84  \ndiv(s7_8)\t3.8  \ndiv(u16_16)\t9.152  \ndiv(s15_16)\t11.232  \ndiv(u32_32)\t30.8434  \ndiv(s31_32)\t34  \ndiv(int8_t)\t3.82171  \ndiv(uint8_t)\t3.82171  \ndiv(int16_t)\t3.8  \ndiv(uint16_t)\t3.82171  \ndiv(int32_t)\t3.82171  \ndiv(uint32_t)\t3.81806  \ndiv(int64_t)\t10.2286  \ndiv(uint64_t)\t8.304  \n\nAmong the slowest types are `long double`. It is likely that they are\nemulated in software. The next slowest operations are fixed-point\nmultiply and divide operations - especially with 64-bit types. This is\nbecause values need to be promoted temporarily to double-width types.\nThis is a known fixed-point technique which inevitably experiences\nslowdown where a 128-bit type is required on a 64-bit system.\n\nHere is a section of the disassembly of the s15:16 multiply call:\n\n    30:   mov    %r14,%rax  \n          mov    %r15,%rax  \n          movslq -0x28(%rbp),%rax  \n          movslq -0x30(%rbp),%rcx  \n          imul   %rax,%rcx  \n          shr    $0x10,%rcx  \n          mov    %ecx,-0x38(%rbp)  \n          mov    %r12,%rax  \n    4c:   movzbl (%rbx),%eax  \n          cmp    $0x1,%eax  \n        ↓ jne    68  \n    54:   mov    0x8(%rbx),%rax  \n          lea    0x1(%rax),%rcx  \n          mov    %rcx,0x8(%rbx)  \n          cmp    0x38(%rbx),%rax  \n        ↑ jb     30\n\nThe two 32-bit numbers are multiplied together and the result shifted\ndown - much as it would if raw `int` values were used. The efficiency\nof this operation varies with the exponent. An exponent of zero should\nmean no shift at all.\n\n### 3-Dimensional Magnitude Squared\n\nA fast `sqrt` implementation has not yet been tested with\n`fixed_point`. (The naive implementation takes over 300ns.) For this\nreason, a magnitude-squared function is measured, combining multiply\nand add operations:\n\n    template <typename FP>\n    constexpr FP magnitude_squared(const FP & x, const FP & y, const FP & z)\n    {\n        return x * x + y * y + z * z;\n    }\n\nOnly real number formats are tested:\n\nfloat  2.42606  \ndouble  2.08  \nlong double  4.5056  \ns3_4  2.768  \ns7_8  2.77577  \ns15_16  2.752  \ns31_32  4.10331  \n\nAgain, the size of the type seems to have the largest impact.\n\n### Circle Intersection\n\nA similar operation includes a comparison and branch:\n\n    template <typename Real>\n    bool circle_intersect_generic(Real x1, Real y1, Real r1, Real x2, Real y2, Real r2)\n    {\n\t    auto x_diff = x2 - x1;\n    \tauto y_diff = y2 - y1;\n\t    auto distance_squared = x_diff * x_diff + y_diff * y_diff;\n\n\t    auto touch_distance = r1 + r2;\n    \tauto touch_distance_squared = touch_distance * touch_distance;\n\n\t    return distance_squared <= touch_distance_squared;\n    }\n\nfloat\t3.46011  \ndouble\t3.48  \nlong double\t6.4  \ns3_4\t3.88  \ns7_8\t4.5312  \ns15_16\t3.82171  \ns31_32\t5.92  \n\nAgain, fixed-point and native performance are comparable.\n"
  },
  {
    "path": "Docs/Proposals/p0037.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n      <meta charset=\"utf-8\" />\n      <title>Fixed_Point_Library_Proposal</title>\n      <style>.markdown-preview, .markdown-preview[data-use-github-style] { font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 1.6; word-wrap: break-word; overflow: scroll; box-sizing: border-box; padding: 20px; background-color: rgb(255, 255, 255); }\n.markdown-preview > :first-child, .markdown-preview[data-use-github-style] > :first-child { margin-top: 0px !important; }\n.markdown-preview > :last-child, .markdown-preview[data-use-github-style] > :last-child { margin-bottom: 0px !important; }\n.markdown-preview a:not([href]), .markdown-preview[data-use-github-style] a:not([href]) { color: inherit; text-decoration: none; }\n.markdown-preview .absent, .markdown-preview[data-use-github-style] .absent { color: rgb(204, 0, 0); }\n.markdown-preview .anchor, .markdown-preview[data-use-github-style] .anchor { position: absolute; top: 0px; left: 0px; display: block; padding-right: 6px; padding-left: 30px; margin-left: -30px; }\n.markdown-preview .anchor:focus, .markdown-preview[data-use-github-style] .anchor:focus { outline: none; }\n.markdown-preview h1, .markdown-preview[data-use-github-style] h1, .markdown-preview h2, .markdown-preview[data-use-github-style] h2, .markdown-preview h3, .markdown-preview[data-use-github-style] h3, .markdown-preview h4, .markdown-preview[data-use-github-style] h4, .markdown-preview h5, .markdown-preview[data-use-github-style] h5, .markdown-preview h6, .markdown-preview[data-use-github-style] h6 { position: relative; margin-top: 1em; margin-bottom: 16px; font-weight: bold; line-height: 1.4; }\n.markdown-preview h1 .octicon-link, .markdown-preview[data-use-github-style] h1 .octicon-link, .markdown-preview h2 .octicon-link, .markdown-preview[data-use-github-style] h2 .octicon-link, .markdown-preview h3 .octicon-link, .markdown-preview[data-use-github-style] h3 .octicon-link, .markdown-preview h4 .octicon-link, .markdown-preview[data-use-github-style] h4 .octicon-link, .markdown-preview h5 .octicon-link, .markdown-preview[data-use-github-style] h5 .octicon-link, .markdown-preview h6 .octicon-link, .markdown-preview[data-use-github-style] h6 .octicon-link { display: none; color: rgb(0, 0, 0); vertical-align: middle; }\n.markdown-preview h1:hover .anchor, .markdown-preview[data-use-github-style] h1:hover .anchor, .markdown-preview h2:hover .anchor, .markdown-preview[data-use-github-style] h2:hover .anchor, .markdown-preview h3:hover .anchor, .markdown-preview[data-use-github-style] h3:hover .anchor, .markdown-preview h4:hover .anchor, .markdown-preview[data-use-github-style] h4:hover .anchor, .markdown-preview h5:hover .anchor, .markdown-preview[data-use-github-style] h5:hover .anchor, .markdown-preview h6:hover .anchor, .markdown-preview[data-use-github-style] h6:hover .anchor { padding-left: 8px; margin-left: -30px; text-decoration: none; }\n.markdown-preview h1:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h1:hover .anchor .octicon-link, .markdown-preview h2:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h2:hover .anchor .octicon-link, .markdown-preview h3:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h3:hover .anchor .octicon-link, .markdown-preview h4:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h4:hover .anchor .octicon-link, .markdown-preview h5:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h5:hover .anchor .octicon-link, .markdown-preview h6:hover .anchor .octicon-link, .markdown-preview[data-use-github-style] h6:hover .anchor .octicon-link { display: inline-block; }\n.markdown-preview h1 tt, .markdown-preview[data-use-github-style] h1 tt, .markdown-preview h2 tt, .markdown-preview[data-use-github-style] h2 tt, .markdown-preview h3 tt, .markdown-preview[data-use-github-style] h3 tt, .markdown-preview h4 tt, .markdown-preview[data-use-github-style] h4 tt, .markdown-preview h5 tt, .markdown-preview[data-use-github-style] h5 tt, .markdown-preview h6 tt, .markdown-preview[data-use-github-style] h6 tt, .markdown-preview h1 code, .markdown-preview[data-use-github-style] h1 code, .markdown-preview h2 code, .markdown-preview[data-use-github-style] h2 code, .markdown-preview h3 code, .markdown-preview[data-use-github-style] h3 code, .markdown-preview h4 code, .markdown-preview[data-use-github-style] h4 code, .markdown-preview h5 code, .markdown-preview[data-use-github-style] h5 code, .markdown-preview h6 code, .markdown-preview[data-use-github-style] h6 code { font-size: inherit; }\n.markdown-preview h1, .markdown-preview[data-use-github-style] h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(238, 238, 238); }\n.markdown-preview h1 .anchor, .markdown-preview[data-use-github-style] h1 .anchor { line-height: 1; }\n.markdown-preview h2, .markdown-preview[data-use-github-style] h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(238, 238, 238); }\n.markdown-preview h2 .anchor, .markdown-preview[data-use-github-style] h2 .anchor { line-height: 1; }\n.markdown-preview h3, .markdown-preview[data-use-github-style] h3 { font-size: 1.5em; line-height: 1.43; }\n.markdown-preview h3 .anchor, .markdown-preview[data-use-github-style] h3 .anchor { line-height: 1.2; }\n.markdown-preview h4, .markdown-preview[data-use-github-style] h4 { font-size: 1.25em; }\n.markdown-preview h4 .anchor, .markdown-preview[data-use-github-style] h4 .anchor { line-height: 1.2; }\n.markdown-preview h5, .markdown-preview[data-use-github-style] h5 { font-size: 1em; }\n.markdown-preview h5 .anchor, .markdown-preview[data-use-github-style] h5 .anchor { line-height: 1.1; }\n.markdown-preview h6, .markdown-preview[data-use-github-style] h6 { font-size: 1em; color: rgb(119, 119, 119); }\n.markdown-preview h6 .anchor, .markdown-preview[data-use-github-style] h6 .anchor { line-height: 1.1; }\n.markdown-preview p, .markdown-preview[data-use-github-style] p, .markdown-preview blockquote, .markdown-preview[data-use-github-style] blockquote, .markdown-preview ul, .markdown-preview[data-use-github-style] ul, .markdown-preview ol, .markdown-preview[data-use-github-style] ol, .markdown-preview dl, .markdown-preview[data-use-github-style] dl, .markdown-preview table, .markdown-preview[data-use-github-style] table, .markdown-preview pre, .markdown-preview[data-use-github-style] pre { margin-top: 0px; margin-bottom: 16px; }\n.markdown-preview hr, .markdown-preview[data-use-github-style] hr { height: 4px; padding: 0px; margin: 16px 0px; border: 0px none; background-color: rgb(231, 231, 231); }\n.markdown-preview ul, .markdown-preview[data-use-github-style] ul, .markdown-preview ol, .markdown-preview[data-use-github-style] ol { padding-left: 2em; }\n.markdown-preview ul.no-list, .markdown-preview[data-use-github-style] ul.no-list, .markdown-preview ol.no-list, .markdown-preview[data-use-github-style] ol.no-list { padding: 0px; list-style-type: none; }\n.markdown-preview ul ul, .markdown-preview[data-use-github-style] ul ul, .markdown-preview ul ol, .markdown-preview[data-use-github-style] ul ol, .markdown-preview ol ol, .markdown-preview[data-use-github-style] ol ol, .markdown-preview ol ul, .markdown-preview[data-use-github-style] ol ul { margin-top: 0px; margin-bottom: 0px; }\n.markdown-preview li > p, .markdown-preview[data-use-github-style] li > p { margin-top: 16px; }\n.markdown-preview dl, .markdown-preview[data-use-github-style] dl { padding: 0px; }\n.markdown-preview dl dt, .markdown-preview[data-use-github-style] dl dt { padding: 0px; margin-top: 16px; font-size: 1em; font-style: italic; font-weight: bold; }\n.markdown-preview dl dd, .markdown-preview[data-use-github-style] dl dd { padding: 0px 16px; margin-bottom: 16px; }\n.markdown-preview blockquote, .markdown-preview[data-use-github-style] blockquote { padding: 0px 15px; color: rgb(119, 119, 119); border-left-width: 4px; border-left-style: solid; border-left-color: rgb(221, 221, 221); }\n.markdown-preview blockquote > :first-child, .markdown-preview[data-use-github-style] blockquote > :first-child { margin-top: 0px; }\n.markdown-preview blockquote > :last-child, .markdown-preview[data-use-github-style] blockquote > :last-child { margin-bottom: 0px; }\n.markdown-preview table, .markdown-preview[data-use-github-style] table { display: block; width: 100%; overflow: auto; word-break: normal; }\n.markdown-preview table th, .markdown-preview[data-use-github-style] table th { font-weight: bold; }\n.markdown-preview table th, .markdown-preview[data-use-github-style] table th, .markdown-preview table td, .markdown-preview[data-use-github-style] table td { padding: 6px 13px; border: 1px solid rgb(221, 221, 221); }\n.markdown-preview table tr, .markdown-preview[data-use-github-style] table tr { border-top-width: 1px; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: rgb(255, 255, 255); }\n.markdown-preview table tr:nth-child(2n), .markdown-preview[data-use-github-style] table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }\n.markdown-preview img, .markdown-preview[data-use-github-style] img { max-width: 100%; box-sizing: border-box; }\n.markdown-preview .emoji, .markdown-preview[data-use-github-style] .emoji { max-width: none; }\n.markdown-preview span.frame, .markdown-preview[data-use-github-style] span.frame { display: block; overflow: hidden; }\n.markdown-preview span.frame > span, .markdown-preview[data-use-github-style] span.frame > span { display: block; float: left; width: auto; padding: 7px; margin: 13px 0px 0px; overflow: hidden; border: 1px solid rgb(221, 221, 221); }\n.markdown-preview span.frame span img, .markdown-preview[data-use-github-style] span.frame span img { display: block; float: left; }\n.markdown-preview span.frame span span, .markdown-preview[data-use-github-style] span.frame span span { display: block; padding: 5px 0px 0px; clear: both; color: rgb(51, 51, 51); }\n.markdown-preview span.align-center, .markdown-preview[data-use-github-style] span.align-center { display: block; overflow: hidden; clear: both; }\n.markdown-preview span.align-center > span, .markdown-preview[data-use-github-style] span.align-center > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: center; }\n.markdown-preview span.align-center span img, .markdown-preview[data-use-github-style] span.align-center span img { margin: 0px auto; text-align: center; }\n.markdown-preview span.align-right, .markdown-preview[data-use-github-style] span.align-right { display: block; overflow: hidden; clear: both; }\n.markdown-preview span.align-right > span, .markdown-preview[data-use-github-style] span.align-right > span { display: block; margin: 13px 0px 0px; overflow: hidden; text-align: right; }\n.markdown-preview span.align-right span img, .markdown-preview[data-use-github-style] span.align-right span img { margin: 0px; text-align: right; }\n.markdown-preview span.float-left, .markdown-preview[data-use-github-style] span.float-left { display: block; float: left; margin-right: 13px; overflow: hidden; }\n.markdown-preview span.float-left span, .markdown-preview[data-use-github-style] span.float-left span { margin: 13px 0px 0px; }\n.markdown-preview span.float-right, .markdown-preview[data-use-github-style] span.float-right { display: block; float: right; margin-left: 13px; overflow: hidden; }\n.markdown-preview span.float-right > span, .markdown-preview[data-use-github-style] span.float-right > span { display: block; margin: 13px auto 0px; overflow: hidden; text-align: right; }\n.markdown-preview code, .markdown-preview[data-use-github-style] code, .markdown-preview tt, .markdown-preview[data-use-github-style] tt { padding: 0.2em 0px; margin: 0px; font-size: 85%; border-radius: 3px; background-color: rgba(0, 0, 0, 0.0392157); }\n.markdown-preview code::before, .markdown-preview[data-use-github-style] code::before, .markdown-preview tt::before, .markdown-preview[data-use-github-style] tt::before, .markdown-preview code::after, .markdown-preview[data-use-github-style] code::after, .markdown-preview tt::after, .markdown-preview[data-use-github-style] tt::after { letter-spacing: -0.2em; content: ' '; }\n.markdown-preview code br, .markdown-preview[data-use-github-style] code br, .markdown-preview tt br, .markdown-preview[data-use-github-style] tt br { display: none; }\n.markdown-preview del code, .markdown-preview[data-use-github-style] del code { text-decoration: inherit; }\n.markdown-preview pre > code, .markdown-preview[data-use-github-style] pre > code { padding: 0px; margin: 0px; font-size: 100%; word-break: normal; white-space: pre; border: 0px; background: transparent; }\n.markdown-preview .highlight, .markdown-preview[data-use-github-style] .highlight { margin-bottom: 16px; }\n.markdown-preview .highlight pre, .markdown-preview[data-use-github-style] .highlight pre, .markdown-preview pre, .markdown-preview[data-use-github-style] pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; border-radius: 3px; background-color: rgb(247, 247, 247); }\n.markdown-preview .highlight pre, .markdown-preview[data-use-github-style] .highlight pre { margin-bottom: 0px; word-break: normal; }\n.markdown-preview pre, .markdown-preview[data-use-github-style] pre { word-wrap: normal; }\n.markdown-preview pre code, .markdown-preview[data-use-github-style] pre code, .markdown-preview pre tt, .markdown-preview[data-use-github-style] pre tt { display: inline; max-width: initial; padding: 0px; margin: 0px; overflow: initial; line-height: inherit; word-wrap: normal; border: 0px; background-color: transparent; }\n.markdown-preview pre code::before, .markdown-preview[data-use-github-style] pre code::before, .markdown-preview pre tt::before, .markdown-preview[data-use-github-style] pre tt::before, .markdown-preview pre code::after, .markdown-preview[data-use-github-style] pre code::after, .markdown-preview pre tt::after, .markdown-preview[data-use-github-style] pre tt::after { content: normal; }\n.markdown-preview kbd, .markdown-preview[data-use-github-style] kbd { display: inline-block; padding: 3px 5px; font-size: 11px; line-height: 10px; color: rgb(85, 85, 85); vertical-align: middle; border-style: solid; border-width: 1px; border-color: rgb(204, 204, 204) rgb(204, 204, 204) rgb(187, 187, 187); border-radius: 3px; box-shadow: rgb(187, 187, 187) 0px -1px 0px inset; background-color: rgb(252, 252, 252); }\n.markdown-preview, .markdown-preview[data-use-github-style], .markdown-preview code, .markdown-preview[data-use-github-style] code { color: rgb(51, 51, 51); }\n.markdown-preview h1, .markdown-preview[data-use-github-style] h1, .markdown-preview h2, .markdown-preview[data-use-github-style] h2, .markdown-preview h3, .markdown-preview[data-use-github-style] h3, .markdown-preview h4, .markdown-preview[data-use-github-style] h4, .markdown-preview h5, .markdown-preview[data-use-github-style] h5, .markdown-preview h6, .markdown-preview[data-use-github-style] h6 { -webkit-font-smoothing: antialiased; cursor: text; }\n.markdown-preview > h1:first-child, .markdown-preview[data-use-github-style] > h1:first-child, .markdown-preview > h1:first-child + h2, .markdown-preview[data-use-github-style] > h1:first-child + h2, .markdown-preview > h2:first-child, .markdown-preview[data-use-github-style] > h2:first-child, .markdown-preview > h3:first-child, .markdown-preview[data-use-github-style] > h3:first-child, .markdown-preview > h4:first-child, .markdown-preview[data-use-github-style] > h4:first-child, .markdown-preview > h5:first-child, .markdown-preview[data-use-github-style] > h5:first-child, .markdown-preview > h6:first-child, .markdown-preview[data-use-github-style] > h6:first-child { margin-top: 0px; padding-top: 0px; }\n.markdown-preview a, .markdown-preview[data-use-github-style] a, .markdown-preview a code, .markdown-preview[data-use-github-style] a code { color: rgb(65, 131, 196); }\n.markdown-preview a:first-child h1, .markdown-preview[data-use-github-style] a:first-child h1, .markdown-preview a:first-child h2, .markdown-preview[data-use-github-style] a:first-child h2, .markdown-preview a:first-child h3, .markdown-preview[data-use-github-style] a:first-child h3, .markdown-preview a:first-child h4, .markdown-preview[data-use-github-style] a:first-child h4, .markdown-preview a:first-child h5, .markdown-preview[data-use-github-style] a:first-child h5, .markdown-preview a:first-child h6, .markdown-preview[data-use-github-style] a:first-child h6 { margin-top: 0px; padding-top: 0px; }\n.markdown-preview h1 + p, .markdown-preview[data-use-github-style] h1 + p, .markdown-preview h2 + p, .markdown-preview[data-use-github-style] h2 + p, .markdown-preview h3 + p, .markdown-preview[data-use-github-style] h3 + p, .markdown-preview h4 + p, .markdown-preview[data-use-github-style] h4 + p, .markdown-preview h5 + p, .markdown-preview[data-use-github-style] h5 + p, .markdown-preview h6 + p, .markdown-preview[data-use-github-style] h6 + p { margin-top: 0px; }\n.markdown-preview li p.first, .markdown-preview[data-use-github-style] li p.first { display: inline-block; }\n.markdown-preview ul li > :first-child, .markdown-preview[data-use-github-style] ul li > :first-child, .markdown-preview ol li > :first-child, .markdown-preview[data-use-github-style] ol li > :first-child, .markdown-preview ul li ul:first-of-type, .markdown-preview[data-use-github-style] ul li ul:first-of-type, .markdown-preview ol li ul:first-of-type, .markdown-preview[data-use-github-style] ol li ul:first-of-type { margin-top: 0px; }\n.markdown-preview ol > li, .markdown-preview[data-use-github-style] ol > li { list-style-type: decimal; }\n.markdown-preview ul > li, .markdown-preview[data-use-github-style] ul > li { list-style-type: disc; }\n.markdown-preview dl dt:first-child, .markdown-preview[data-use-github-style] dl dt:first-child { padding: 0px; }\n.markdown-preview dl dt > :first-child, .markdown-preview[data-use-github-style] dl dt > :first-child { margin-top: 0px; }\n.markdown-preview dl dt > :last-child, .markdown-preview[data-use-github-style] dl dt > :last-child { margin-bottom: 0px; }\n.markdown-preview dl dd > :first-child, .markdown-preview[data-use-github-style] dl dd > :first-child { margin-top: 0px; }\n.markdown-preview dl dd > :last-child, .markdown-preview[data-use-github-style] dl dd > :last-child { margin-bottom: 0px; }\n.markdown-preview blockquote p, .markdown-preview[data-use-github-style] blockquote p { font-size: 16px; line-height: 1.5; }\n.markdown-preview pre.editor-colors, .markdown-preview[data-use-github-style] pre.editor-colors { padding: 16px; overflow: auto; font-size: 84%; line-height: 1.45; border-radius: 3px; background-color: rgb(255, 255, 255); }\n.markdown-preview pre.editor-colors, .markdown-preview[data-use-github-style] pre.editor-colors { margin-bottom: 16px; word-break: normal; }\n.markdown-preview code, .markdown-preview[data-use-github-style] code, .markdown-preview tt, .markdown-preview[data-use-github-style] tt, .markdown-preview pre.editor-colors, .markdown-preview[data-use-github-style] pre.editor-colors { font-family: Consolas, 'Liberation Mono', Courier, monospace; }\n.markdown-preview .emoji, .markdown-preview[data-use-github-style] .emoji { height: 20px; width: 20px; }\n.bracket-matcher .region {\n  border-bottom: 1px dotted lime;\n  position: absolute;\n}\n\n.spell-check-misspelling .region {\n  border-bottom: 1px dashed rgba(250, 128, 114, 0.5);\n}\n\npre.editor-colors,\n.host {\n  background-color: #ffffff;\n  color: #555555;\n}\npre.editor-colors .invisible-character,\n.host .invisible-character {\n  color: rgba(85, 85, 85, 0.2);\n}\npre.editor-colors .indent-guide,\n.host .indent-guide {\n  color: rgba(85, 85, 85, 0.2);\n}\npre.editor-colors .wrap-guide,\n.host .wrap-guide {\n  background-color: rgba(85, 85, 85, 0.2);\n}\npre.editor-colors .gutter,\n.host .gutter {\n  color: #555555;\n  background: #ffffff;\n}\npre.editor-colors .gutter .line-number.folded,\n.host .gutter .line-number.folded,\npre.editor-colors .gutter .line-number:after,\n.host .gutter .line-number:after,\npre.editor-colors .fold-marker:after,\n.host .fold-marker:after {\n  color: #e87b00;\n}\npre.editor-colors .invisible,\n.host .invisible {\n  color: #555;\n}\npre.editor-colors .selection .region,\n.host .selection .region {\n  background-color: #e1e1e1;\n}\npre.editor-colors.is-focused .cursor,\n.host.is-focused .cursor {\n  border-color: #000000;\n}\npre.editor-colors.is-focused .selection .region,\n.host.is-focused .selection .region {\n  background-color: #afc4da;\n}\npre.editor-colors.is-focused .line-number.cursor-line-no-selection,\n.host.is-focused .line-number.cursor-line-no-selection,\npre.editor-colors.is-focused .line.cursor-line,\n.host.is-focused .line.cursor-line {\n  background-color: rgba(255, 255, 134, 0.34);\n}\npre.editor-colors .source.gfm,\n.host .source.gfm {\n  color: #444;\n}\npre.editor-colors .gfm .markup.heading,\n.host .gfm .markup.heading {\n  color: #111;\n}\npre.editor-colors .gfm .link,\n.host .gfm .link {\n  color: #888;\n}\npre.editor-colors .gfm .variable.list,\n.host .gfm .variable.list {\n  color: #888;\n}\npre.editor-colors .markdown .paragraph,\n.host .markdown .paragraph {\n  color: #444;\n}\npre.editor-colors .markdown .heading,\n.host .markdown .heading {\n  color: #111;\n}\npre.editor-colors .markdown .link,\n.host .markdown .link {\n  color: #888;\n}\npre.editor-colors .markdown .link .string,\n.host .markdown .link .string {\n  color: #888;\n}\n.host(.is-focused) .cursor {\n  border-color: #000000;\n}\n.host(.is-focused) .selection .region {\n  background-color: #afc4da;\n}\n.host(.is-focused) .line-number.cursor-line-no-selection,\n.host(.is-focused) .line.cursor-line {\n  background-color: rgba(255, 255, 134, 0.34);\n}\n.comment {\n  color: #999988;\n  font-style: italic;\n}\n.string {\n  color: #D14;\n}\n.string .source,\n.string .meta.embedded.line {\n  color: #5A5A5A;\n}\n.string .punctuation.section.embedded {\n  color: #920B2D;\n}\n.string .punctuation.section.embedded .source {\n  color: #920B2D;\n}\n.constant.numeric {\n  color: #D14;\n}\n.constant.language {\n  color: #606aa1;\n}\n.constant.character,\n.constant.other {\n  color: #606aa1;\n}\n.constant.symbol {\n  color: #990073;\n}\n.constant.numeric.line-number.find-in-files .match {\n  color: rgba(143, 190, 0, 0.63);\n}\n.variable {\n  color: #008080;\n}\n.variable.parameter {\n  color: #606aa1;\n}\n.keyword {\n  color: #222;\n  font-weight: bold;\n}\n.keyword.unit {\n  color: #445588;\n}\n.keyword.special-method {\n  color: #0086B3;\n}\n.storage {\n  color: #222;\n}\n.storage.type {\n  color: #222;\n}\n.entity.name.class {\n  text-decoration: underline;\n  color: #606aa1;\n}\n.entity.other.inherited-class {\n  text-decoration: underline;\n  color: #606aa1;\n}\n.entity.name.function {\n  color: #900;\n}\n.entity.name.tag {\n  color: #008080;\n}\n.entity.other.attribute-name {\n  color: #458;\n  font-weight: bold;\n}\n.entity.name.filename.find-in-files {\n  color: #E6DB74;\n}\n.support.constant,\n.support.function,\n.support.type {\n  color: #458;\n}\n.support.class {\n  color: #008080;\n}\n.invalid {\n  color: #F8F8F0;\n  background-color: #00A8C6;\n}\n.invalid.deprecated {\n  color: #F8F8F0;\n  background-color: #8FBE00;\n}\n.meta.structure.dictionary.json > .string.quoted.double.json,\n.meta.structure.dictionary.json > .string.quoted.double.json .punctuation.string {\n  color: #000080;\n}\n.meta.structure.dictionary.value.json > .string.quoted.double.json {\n  color: #d14;\n}\n.meta.diff,\n.meta.diff.header {\n  color: #75715E;\n}\n.css.support.property-name {\n  font-weight: bold;\n  color: #333;\n}\n.css.constant {\n  color: #099;\n}\n.bracket-matcher .region {\n  background-color: #C9C9C9;\n  opacity: .7;\n  border-bottom: 0 none;\n}\n</style>\n  </head>\n  <body class='markdown-preview'><p><strong>Document number</strong>: LEWG, EWG, SG14, SG6: P0037R0<br><strong>Date</strong>: 2015-09-28<br><strong>Project</strong>: Programming Language C++, Library Evolution WG, SG14<br><strong>Reply-to</strong>: John McFarlane, <a href=\"mailto:fixed-point@john.mcfarlane.name\">fixed-point@john.mcfarlane.name</a></p>\n<h1 id=\"fixed-point-real-numbers\">Fixed-Point Real Numbers</h1>\n<h2 id=\"i-introduction\">I. Introduction</h2>\n<p>This proposal introduces a system for performing binary fixed-point\narithmetic using built-in integral types.</p>\n<h2 id=\"ii-motivation\">II. Motivation</h2>\n<p>Floating-point types are an exceedingly versatile and widely supported\nmethod of expressing real numbers on modern architectures.</p>\n<p>However, there are certain situations where fixed-point arithmetic is\npreferable. Some systems lack native floating-point registers and must\nemulate them in software. Many others are capable of performing some\nor all operations more efficiently using integer arithmetic. Certain\napplications can suffer from the variability in precision which comes\nfrom a dynamic radix point <a href=\"http://www.pathengine.com/Contents/Overview/FundamentalConcepts/WhyIntegerCoordinates/page.php\">[1]</a>.\nIn situations where a variable exponent is not desired, it takes\nvaluable space away from the significand and reduces precision.</p>\n<p>Built-in integer types provide the basis for an efficient\nrepresentation of binary fixed-point real numbers. However, laborious,\nerror-prone steps are required to normalize the results of certain\noperations and to convert to and from fixed-point types.</p>\n<p>A set of tools for defining and manipulating fixed-point types is\nproposed. These tools are designed to make work easier for those who\ntraditionally use integers to perform low-level, high-performance\nfixed-point computation.</p>\n<h2 id=\"iii-impact-on-the-standard\">III. Impact On the Standard</h2>\n<p>This proposal is a pure library extension. It does not require\nchanges to any standard classes, functions or headers.</p>\n<h2 id=\"iv-design-decisions\">IV. Design Decisions</h2>\n<p>The design is driven by the following aims in roughly descending\norder:</p>\n<ol>\n<li>to automate the task of using integer types to perform low-level\nbinary fixed-point arithmetic;</li>\n<li>to facilitate a style of code that is intuitive to anyone who is\ncomfortable with integer and floating-point arithmetic;</li>\n<li>to avoid type promotion, implicit conversion or other behavior that\nmight lead to surprising results and</li>\n<li>to preserve significant digits at the expense of insignificant\ndigits, i.e. to prefer underflow to overflow.</li>\n</ol>\n<h3 id=\"class-template\">Class Template</h3>\n<p>Fixed-point numbers are specializations of</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>class&nbsp;fixed_point;</span></span></span></div></pre><p>where the template parameters are described as follows.</p>\n<h4 id=\"-reprtype-type-template-parameter\"><code>ReprType</code> Type Template Parameter</h4>\n<p>This parameter identifies the capacity and signedness of the\nunderlying type used to represent the value. In other words, the size\nof the resulting type will be <code>sizeof(ReprType)</code> and it will be\nsigned iff <code>is_signed&lt;ReprType&gt;::value</code> is true. The default is\n<code>int</code>.</p>\n<p><code>ReprType</code> must be a fundamental integral type and should not be the\nlargest size. Suitable types include: <code>std::int8_t</code>, <code>std::uint8_t</code>,\n<code>std::int16_t</code>, <code>std::uint16_t</code>, <code>std::int32_t</code> and <code>std::uint32_t</code>.\nIn limited situations, <code>std::int64_t</code> and <code>std::uint64_t</code> can be used.\nThe  reasons for these limitations relate to the difficulty in finding\na type that is suitable for performing lossless integer\nmultiplication.</p>\n<h4 id=\"-exponent-non-type-template-parameter\"><code>Exponent</code> Non-Type Template Parameter</h4>\n<p>The exponent of a fixed-point type is the equivalent of the exponent\nfield in a floating-point type and shifts the stored value by the\nrequisite number of bits necessary to produce the desired range. The\ndefault value of <code>Exponent</code> is zero, giving <code>fixed_point&lt;T&gt;</code> the same\nrange as <code>T</code>.</p>\n<p>The resolution of a specialization of <code>fixed_point</code> is</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>pow(2,&nbsp;Exponent)</span></span></span></div></pre><p>and the minimum and maximum values are</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>std::numeric_limits&lt;ReprType&gt;::min()&nbsp;*&nbsp;pow(2,&nbsp;Exponent)</span></span></span></div></pre><p>and</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>std::numeric_limits&lt;ReprType&gt;::max()&nbsp;*&nbsp;pow(2,&nbsp;Exponent)</span></span></span></div></pre><p>respectively.</p>\n<p>Any usage that results in values of <code>Exponent</code> which lie outside the\nrange, (<code>INT_MIN / 2</code>, <code>INT_MAX / 2</code>), may result in undefined\nbehavior and/or overflow or underflow. This range of exponent values\nis far in excess of the largest built-in floting-point type and should\nbe adequate for all intents and purposes.</p>\n<h3 id=\"-make_fixed-and-make_ufixed-helper-type\"><code>make_fixed</code> and <code>make_ufixed</code> Helper Type</h3>\n<p>The <code>Exponent</code> template parameter is versatile and concise. It is an\nintuitive scale to use when considering the full range of positive and\nnegative exponents a fixed-point type might possess. It also\ncorresponds to the exponent field of built-in floating-point types.</p>\n<p>However, most fixed-point formats can be described more intuitively by\nthe cardinal number of integer and/or fractional digits they contain.\nMost users will prefer to distinguish fixed-point types using these\nparameters.</p>\n<p>For this reason, two aliases are defined in the style of\n<code>make_signed</code>.</p>\n<p>These aliases are declared as:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;unsigned&nbsp;IntegerDigits,&nbsp;unsigned&nbsp;FractionalDigits&nbsp;=&nbsp;0,&nbsp;bool&nbsp;IsSigned&nbsp;=&nbsp;true&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;make_fixed;</span></span></span></div></pre><p>and</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;unsigned&nbsp;IntegerDigits,&nbsp;unsigned&nbsp;FractionalDigits&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>using&nbsp;make_ufixed;</span></span></span></div></pre><p>They resolve to a <code>fixed_point</code> specialization with the given\nsignedness and number of integer and fractional digits. They may\ncontain additional integer and fractional digits.</p>\n<p>For example, one could define and initialize an 8-bit, unsigned,\nfixed-point variable with four integer digits and four fractional\ndigits:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;4,&nbsp;4&gt;&nbsp;value&nbsp;{&nbsp;15.9375&nbsp;};</span></span></span></div></pre><p>or a 32-bit, signed, fixed-point number with two integer digits and 29\nfractional digits:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_fixed&lt;2,&nbsp;29&gt;&nbsp;value&nbsp;{&nbsp;3.141592653&nbsp;};</span></span></span></div></pre><h3 id=\"conversion\">Conversion</h3>\n<p>Fixed-point numbers can be explicitly converted to and from built-in\narithmetic types.</p>\n<p>While effort is made to ensure that significant digits are not lost\nduring conversion, no effort is made to avoid rounding errors.\nWhatever would happen when converting to and from an integer type\nlargely applies to <code>fixed_point</code> objects also. For example:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;4,&nbsp;4&gt;(.006)&nbsp;==&nbsp;make_ufixed&lt;4,&nbsp;4&gt;(0)</span></span></span></div></pre><p>...equates to <code>true</code> and is considered a acceptable rounding error.</p>\n<h3 id=\"operator-overloads\">Operator Overloads</h3>\n<p>Any operators that might be applied to integer types can also be\napplied to fixed-point types. A guiding principle of operator\noverloads is that they perform as little run-time computation as is\npractically possible.</p>\n<p>With the exception of shift and comparison operators, binary operators\ncan take any combination of:</p>\n<ul>\n<li>one or two fixed-point arguments and</li>\n<li>zero or one arguments of any arithmetic type, i.e. a type for which\n<code>is_arithmetic</code> is true.</li>\n</ul>\n<p>Where the inputs are not identical fixed-point types, a simple set of\npromotion-like rules are applied to determine the return type:</p>\n<ol>\n<li>If both arguments are fixed-point, a type is chosen which is the\nsize of the larger type, is signed if either input is signed and\nhas the maximum integer bits of the two inputs, i.e. cannot lose\nhigh-significance bits through conversion alone.</li>\n<li>If one of the arguments is a floating-point type, then the type of\nthe result is the smallest floating-point type of equal or greater\nsize than the inputs.</li>\n<li>If one of the arguments is an integral type, then the result is the\nother, fixed-point type.</li>\n</ol>\n<p>Some examples:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;5,&nbsp;3&gt;{8}&nbsp;+&nbsp;make_ufixed&lt;4,&nbsp;4&gt;{3}&nbsp;==&nbsp;make_ufixed&lt;5,&nbsp;3&gt;{11};&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;5,&nbsp;3&gt;{8}&nbsp;+&nbsp;3&nbsp;==&nbsp;make_ufixed&lt;5,&nbsp;3&gt;{11};&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;5,&nbsp;3&gt;{8}&nbsp;+&nbsp;float{3}&nbsp;==&nbsp;float{11};&nbsp;&nbsp;</span></span></span></div></pre><p>The reasoning behind this choice is a combination of predictability\nand performance. It is explained for each rule as follows:</p>\n<ol>\n<li>ensures that the least computation is performed where fixed-point\ntypes are used exclusively. Aside from multiplication and division\nrequiring shift operations, should require similar computational\ncosts to equivalent integer operations;</li>\n<li>loosely follows the promotion rules for mixed-mode arithmetic,\nensures values with exponents far beyond the range of the\nfixed-point type are catered for and avoids costly conversion from\nfloating-point to integer and</li>\n<li>preserves the input fixed-point type whose range is far more likely\nto be of deliberate importance to the operation.</li>\n</ol>\n<p>Shift operator overloads require an integer type as the right-hand\nparameter and return a type which is adjusted to accommodate the new\nvalue without risk of overflow or underflow.</p>\n<p>Comparison operators convert the inputs to a common result type\nfollowing the rules above before performing a comparison and returning\n<code>true</code> or <code>false</code>.</p>\n<h4 id=\"overflow\">Overflow</h4>\n<p>Because arithmetic operators return a result of equal capacity to\ntheir inputs, they carry a risk of overflow. For instance,</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_fixed&lt;4,&nbsp;3&gt;(15)&nbsp;+&nbsp;make_fixed&lt;4,&nbsp;3&gt;(1)</span></span></span></div></pre><p>causes overflow because because a type with 4 integer bits cannot\nstore a value of 16.</p>\n<p>Overflow of any bits in a signed or unsigned fixed-point type is\nclassed as undefined behavior. This is a minor deviation from\nbuilt-in integer arithmetic where only signed overflow results in\nundefined behavior.</p>\n<h4 id=\"underflow\">Underflow</h4>\n<p>The other typical cause of lost bits is underflow where, for example,</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_fixed&lt;7,&nbsp;0&gt;(15)&nbsp;/&nbsp;make_fixed&lt;7,&nbsp;0&gt;(2)</span></span></span></div></pre><p>results in a value of 7. This results in loss of precision but is\ngenerally considered acceptable.</p>\n<p>However, when all bits are lost due to underflow, the value is said\nto be flushed and this is classed as undefined behavior.</p>\n<h3 id=\"dealing-with-overflow-and-flushes\">Dealing With Overflow and Flushes</h3>\n<p>Errors resulting from overflow and flushes are two of the biggest\nheadaches related to fixed-point arithmetic. Integers suffer the same\nkinds of errors but are somewhat easier to reason about as they lack\nfractional digits. Floating-point numbers are largely shielded from\nthese errors by their variable exponent and implicit bit.</p>\n<p>Three strategies for avoiding overflow in fixed-point types are\npresented:</p>\n<ol>\n<li>simply leave it to the user to avoid overflow;</li>\n<li>promote the result to a larger type to ensure sufficient capacity\nor</li>\n<li>adjust the exponent of the result upward to ensure that the top\nlimit of the type is sufficient to preserve the most significant\ndigits at the expense of the less significant digits.</li>\n</ol>\n<p>For arithmetic operators, choice 1) is taken because it most closely\nfollows the behavior of integer types. Thus it should cause the least\nsurprise to the fewest users. This makes it far easier to reason\nabout in code where functions are written with a particular type in\nmind. It also requires the least computation in most cases.</p>\n<p>Choices 2) and 3) are more robust to overflow events. However, they\nrepresent different trade-offs and neither one is the best fit in all\nsituations. For these reasons, they are presented as named functions.</p>\n<h4 id=\"type-promotion\">Type Promotion</h4>\n<p>Function template, <code>promote</code>, borrows a term from the language\nfeature which avoids integer overflow prior to certain operations. It\ntakes a <code>fixed_point</code> object and returns the same value represented\nby a larger <code>fixed_point</code> specialization.</p>\n<p>For example,</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>promote(make_fixed&lt;5,&nbsp;2&gt;(15.5))</span></span></span></div></pre><p>is equivalent to</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_fixed&lt;11,&nbsp;4&gt;(15.5)</span></span></span></div></pre><p>Complimentary function template, <code>demote</code>, reverses the process,\nreturning a value of a smaller type.</p>\n<h4 id=\"named-arithmetic-functions\">Named Arithmetic Functions</h4>\n<p>The following named function templates can be used as a hassle-free\nalternative to arithmetic operators in situations where the aim is\nto avoid overflow.</p>\n<p>Unary functions:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>trunc_reciprocal,&nbsp;trunc_square,&nbsp;trunc_sqrt,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>promote_reciprocal,&nbsp;promote_square</span></span></span></div></pre><p>Binary functions:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>trunc_add,&nbsp;trunc_subtract,&nbsp;trunc_multiply,&nbsp;trunc_divide</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>trunc_shift_left,&nbsp;trunc_shift_right,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>promote_add,&nbsp;promote_sub,&nbsp;promote_multiply,&nbsp;promote_divide</span></span></span></div></pre><p>Some notes:</p>\n<ol>\n<li>The <code>trunc_</code> functions return the result as a type no larger than\nthe inputs and with an exponent adjusted to avoid overflow;</li>\n<li>the <code>promote_</code> functions return the result as a type large enough\nto avoid overflow and underflow;</li>\n<li>the <code>_multiply</code> and <code>_square</code> functions are not guaranteed to be\navailable for 64-bit types;</li>\n<li>the <code>_multiply</code> and <code>_square</code> functions produce undefined behavior\nwhen all input parameters are the <em>most negative number</em>;</li>\n<li>the <code>_square</code> functions return an unsigned type;</li>\n<li>the <code>_add</code>, <code>_subtract</code>, <code>_multiply</code> and <code>_divide</code> functions take\nheterogeneous <code>fixed_point</code> specializations;</li>\n<li>the <code>_divide</code> and <code>_reciprocal</code> functions in no way guard against\ndivide-by-zero errors;</li>\n<li>the <code>trunc_shift_</code> functions return results of the same type as\ntheir first input parameter and</li>\n<li>the list is by no means complete.</li>\n</ol>\n<h3 id=\"example\">Example</h3>\n<p>The following example calculates the magnitude of a 3-dimensional vector.</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Fp&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;magnitude(const&nbsp;Fp&nbsp;&amp;&nbsp;x,&nbsp;const&nbsp;Fp&nbsp;&amp;&nbsp;y,&nbsp;const&nbsp;Fp&nbsp;&amp;&nbsp;z)</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>-&gt;&nbsp;decltype(trunc_sqrt(trunc_add(trunc_square(x),&nbsp;trunc_square(y),&nbsp;trunc_square(z))))</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>{</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>return&nbsp;trunc_sqrt(trunc_add(trunc_square(x),&nbsp;trunc_square(y),&nbsp;trunc_square(z)));</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>}</span></span></span></div></pre><p>Calling the above function as follows</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>static_cast&lt;double&gt;(magnitude(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>make_ufixed&lt;4,&nbsp;12&gt;(1),</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;make_ufixed&lt;4,&nbsp;12&gt;(4),</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;make_ufixed&lt;4,&nbsp;12&gt;(9)));</span></span></span></div></pre><p>returns the value, 9.890625.</p>\n<h2 id=\"v-technical-specification\">V. Technical Specification</h2>\n<h3 id=\"header-fixed_point-synopsis\">Header \\<fixed_point\\> Synopsis</fixed_point\\></h3>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>namespace&nbsp;std&nbsp;{</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;&nbsp;class&nbsp;fixed_point;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;unsigned&nbsp;IntegerDigits,&nbsp;unsigned&nbsp;FractionalDigits&nbsp;=&nbsp;0,&nbsp;bool&nbsp;IsSigned&nbsp;=&nbsp;true&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;make_fixed;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;unsigned&nbsp;IntegerDigits,&nbsp;unsigned&nbsp;FractionalDigits&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;make_ufixed;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;IntegerDigits&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;make_fixed_from_repr;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;from)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;demote_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>demote_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;demote(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;from)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator==(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator!=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator&lt;(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator&gt;(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator&gt;=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;bool&nbsp;operator&lt;=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;operator-(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;operator+(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;operator-(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator+=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator-=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator*=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator/=(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator==(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator!=(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator&lt;(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator&gt;(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator&gt;=(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator&lt;=(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator+(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator-(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator*(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator/(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;Integer&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator*(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Integer&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;Integer&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator/(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Integer&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Integer,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator*(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Integer&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Integer,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator/(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Integer&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;Float&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator*(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Float&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;LhsExponent,&nbsp;class&nbsp;Float&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator/(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;fixed_point&lt;LhsReprType,&nbsp;LhsExponent&gt;&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;Float&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Float,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator*(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Float&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Float,&nbsp;class&nbsp;RhsReprType,&nbsp;int&nbsp;RhsExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;auto&nbsp;operator/(</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>const&nbsp;Float&nbsp;&amp;&nbsp;lhs,</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;fixed_point&lt;RhsReprType,&nbsp;RhsExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;Exponent,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator+=(fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;Exponent,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;operator-=(fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;template&nbsp;&lt;class&nbsp;Rhs,&nbsp;typename&nbsp;std::enable_if&lt;std::is_arithmetic&lt;Rhs&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;::operator*=(const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;LhsReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;template&nbsp;&lt;class&nbsp;Rhs,&nbsp;typename&nbsp;std::enable_if&lt;std::is_arithmetic&lt;Rhs&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;&nbsp;&amp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fixed_point&lt;LhsReprType,&nbsp;Exponent&gt;::operator/=(const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>sqrt(const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;x)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint,&nbsp;unsigned&nbsp;N&nbsp;=&nbsp;2&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_add_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint,&nbsp;class&nbsp;...&nbsp;Tail&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_add_result&lt;FixedPoint,&nbsp;sizeof...(Tail)&nbsp;+&nbsp;1&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;constexpr&nbsp;trunc_add(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;addend1,&nbsp;const&nbsp;Tail&nbsp;&amp;&nbsp;...&nbsp;addend_tail);</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&nbsp;=&nbsp;Lhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_subtract_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_subtract_result&lt;Lhs,&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_subtract(const&nbsp;Lhs&nbsp;&amp;&nbsp;minuend,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;subtrahend);</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&nbsp;=&nbsp;Lhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_multiply_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_multiply_result&lt;Lhs,&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_multiply(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPointDividend,&nbsp;class&nbsp;FixedPointDivisor&nbsp;=&nbsp;FixedPointDividend&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_divide_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPointDividend,&nbsp;class&nbsp;FixedPointDivisor&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_divide_result&lt;FixedPointDividend,&nbsp;FixedPointDivisor&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_divide(const&nbsp;FixedPointDividend&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;FixedPointDivisor&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_reciprocal_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_reciprocal_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_reciprocal(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;fixed_point)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_square_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_square_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_square(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;root)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;trunc_sqrt_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_sqrt_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;trunc_sqrt(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;square)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;int&nbsp;Integer,&nbsp;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&nbsp;+&nbsp;Integer&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_shift_left(const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;fp)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;int&nbsp;Integer,&nbsp;class&nbsp;ReprType,&nbsp;int&nbsp;Exponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&nbsp;-&nbsp;Integer&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>trunc_shift_right(const&nbsp;fixed_point&lt;ReprType,&nbsp;Exponent&gt;&nbsp;&amp;&nbsp;fp)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint,&nbsp;unsigned&nbsp;N&nbsp;=&nbsp;2&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_add_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint,&nbsp;class&nbsp;...&nbsp;Tail&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_add_result&lt;FixedPoint,&nbsp;sizeof...(Tail)&nbsp;+&nbsp;1&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote_add(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;addend1,&nbsp;const&nbsp;Tail&nbsp;&amp;&nbsp;...&nbsp;addend_tail);</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&nbsp;=&nbsp;Lhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_subtract_result</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_subtract_result&lt;Lhs,&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote_subtract(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&nbsp;=&nbsp;Lhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_multiply_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_multiply_result&lt;Lhs,&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote_multiply(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&nbsp;=&nbsp;Lhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_divide_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Lhs,&nbsp;class&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_divide_result&lt;Lhs,&nbsp;Rhs&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote_divide(const&nbsp;Lhs&nbsp;&amp;&nbsp;lhs,&nbsp;const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;promote_square_result;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>promote_square_result&lt;FixedPoint&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;promote_square(const&nbsp;FixedPoint&nbsp;&amp;&nbsp;root)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>}</span></span></span></div></pre><h4 id=\"-fixed_point-class-template\"><code>fixed_point&lt;&gt;</code> Class Template</h4>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;ReprType&nbsp;=&nbsp;int,&nbsp;int&nbsp;Exponent&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>class&nbsp;fixed_point</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>{</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>public:</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>using&nbsp;repr_type&nbsp;=&nbsp;ReprType;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;static&nbsp;int&nbsp;exponent;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;constexpr&nbsp;static&nbsp;int&nbsp;digits;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;constexpr&nbsp;static&nbsp;int&nbsp;integer_digits;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;constexpr&nbsp;static&nbsp;int&nbsp;fractional_digits;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point()&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;_impl::is_integral&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;fixed_point(S&nbsp;s)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;std::is_floating_point&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;fixed_point(S&nbsp;s)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FromReprType,&nbsp;int&nbsp;FromExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;fixed_point(const&nbsp;fixed_point&lt;FromReprType,&nbsp;FromExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;_impl::is_integral&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&nbsp;&amp;&nbsp;operator=(S&nbsp;s)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;std::is_floating_point&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&nbsp;&amp;&nbsp;operator=(S&nbsp;s)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;FromReprType,&nbsp;int&nbsp;FromExponent&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&nbsp;&amp;&nbsp;operator=(const&nbsp;fixed_point&lt;FromReprType,&nbsp;FromExponent&gt;&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;_impl::is_integral&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;operator&nbsp;S()&nbsp;const&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;S,&nbsp;typename&nbsp;std::enable_if&lt;std::is_floating_point&lt;S&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;operator&nbsp;S()&nbsp;const&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>explicit&nbsp;constexpr&nbsp;operator&nbsp;bool()&nbsp;const&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Rhs,&nbsp;typename&nbsp;std::enable_if&lt;std::is_arithmetic&lt;Rhs&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&nbsp;&amp;operator*=(const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>template&nbsp;&lt;class&nbsp;Rhs,&nbsp;typename&nbsp;std::enable_if&lt;std::is_arithmetic&lt;Rhs&gt;::value,&nbsp;int&gt;::type&nbsp;Dummy&nbsp;=&nbsp;0&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>fixed_point&nbsp;&amp;&nbsp;operator/=(const&nbsp;Rhs&nbsp;&amp;&nbsp;rhs)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>constexpr&nbsp;repr_type&nbsp;data()&nbsp;const&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;static&nbsp;constexpr&nbsp;fixed_point&nbsp;from_data(repr_type&nbsp;repr)&nbsp;noexcept;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>};</span></span></span></div></pre><h2 id=\"vi-future-issues\">VI. Future Issues</h2>\n<h3 id=\"library-support\">Library Support</h3>\n<p>Because the aim is to provide an alternative to existing arithmetic\ntypes which are supported by the standard library, it is conceivable\nthat a future proposal might specialize existing class templates and\noverload existing functions.</p>\n<p>Possible candidates for overloading include the functions defined in\n\\<cmath\\> and a templated specialization of <code>numeric_limits</code>. A new type\ntrait, <code>is_fixed_point</code>, would also be useful.</cmath\\></p>\n<p>While <code>fixed_point</code> is intended to provide drop-in replacements to\nexisting built-ins, it may be preferable to deviate slightly from the\nbehavior of certain standard functions. For example, overloads of\nfunctions from \\<cmath\\> will be considerably less concise, efficient\nand versatile if they obey rules surrounding error cases. In\nparticular, the guarantee of setting <code>errno</code> in the case of an error\nprevents a function from being defined as pure. This highlights a\nwider issue surrounding the adoption of the functional approach and\ncompile-time computation that is beyond the scope of this document.</cmath\\></p>\n<h3 id=\"alternatives-to-built-in-integer-types\">Alternatives to Built-in Integer Types</h3>\n<p>The reason that <code>ReprType</code> is restricted to built-in integer types\nis that a number of features require the use of a higher - or\nlower-capacity type. Supporting alias templates are defined to\nprovide <code>fixed_point</code> with the means to invoke integer types of\nspecific capacity and signedness at compile time.</p>\n<p>There is no general purpose way of deducing a higher or\nlower-capacity type given a source type in the same manner as\n<code>make_signed</code> and <code>make_unsigned</code>. If there were, this might be\nadequate to allow alternative choices for <code>ReprType</code>.</p>\n<h3 id=\"bounded-integers\">Bounded Integers</h3>\n<p>The bounded::integer library <a href=\"http://doublewise.net/c++/bounded/\">[2]</a>\nexemplifies the benefits of keeping track of ranges of values in\narithmetic types at compile time.</p>\n<p>To a limited extent, the <code>trunc_</code> functions defined here also keep\ntrack of - and modify - the limits of values. However, a combination\nof techniques is capable of producing superior results.</p>\n<p>For instance, consider the following expression:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>make_ufixed&lt;2,&nbsp;6&gt;&nbsp;three(3);</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>auto&nbsp;n&nbsp;=&nbsp;trunc_square(trunc_square(three));</span></span></span></div></pre><p>The type of <code>n</code> is <code>make_ufixed&lt;8, 0&gt;</code> but its value does not\nexceed 81. Hence, an integer bit has been wasted. It may be possible\nto track more accurate limits in the same manner as the\nbounded::integer library in order to improve the precision of types\nreturned by <code>trunc_</code> functions. For this reason, the exact value of\nthe exponents of these return types is not given.</p>\n<p>Notes:</p>\n<ul>\n<li>Bounded::integer is already supported by fixed-point library,\nfp <a href=\"https://github.com/mizvekov/fp\">[3]</a>.</li>\n<li>A similar library is the boost constrained_value library\n<a href=\"http://rk.hekko.pl/constrained_value/\">[4]</a>.</li>\n</ul>\n<h3 id=\"alternative-policies\">Alternative Policies</h3>\n<p>The behavior of the types specialized from <code>fixed_point</code> represent\none sub-set of all potentially desirable behaviors. Alternative\ncharacteristics include:</p>\n<ul>\n<li>different rounding strategies - other than truncation;</li>\n<li>overflow and underflow checks - possibly throwing exceptions;</li>\n<li>operator return type - adopting <code>trunc_</code> or <code>promote_</code> behavior;</li>\n<li>default-initialize to zero - currently uninitialized and</li>\n<li>saturation arithmetic - as opposed to modular arithmetic.</li>\n</ul>\n<p>One way to extend <code>fixed_point</code> to cover these alternatives would be\nto add non-type template parameters containing bit flags or enumerated\ntypes. The default set of values would reflect <code>fixed_point</code> as it\nstands currently.</p>\n<h2 id=\"vii-prior-art\">VII. Prior Art</h2>\n<p>Many examples of fixed-point support in C and C++ exist. While almost\nall of them aim for low run-time cost and expressive alternatives to\nraw integer manipulation, they vary greatly in detail and in terms of\ntheir interface.</p>\n<p>One especially interesting dichotomy is between solutions which offer\na discrete selection of fixed-point types and libraries which contain\na continuous range of exponents through type parameterization.</p>\n<h3 id=\"n1169\">N1169</h3>\n<p>One example of the former is found in proposal N1169\n<a href=\"http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf\">[5]</a>,\nthe intent of which is to expose features found in certain embedded\nhardware. It introduces a succinct set of language-level fixed-point\ntypes and impose constraints on the number of integer or fractional\ndigits each can possess.</p>\n<p>As with all examples of discrete-type fixed-point support, the limited\nchoice of exponents is a considerable restriction on the versatility\nand expressiveness of the API.</p>\n<p>Nevertheless, it may be possible to harness performance gains provided\nby N1169 fixed-point types through explicit template specialization.\nThis is likely to be a valuable proposition to potential users of the\nlibrary who find themselves targeting platforms which support\nfixed-point arithmetic at the hardware level.</p>\n<h3 id=\"n3352\">N3352</h3>\n<p>There are many other C++ libraries available which fall into the\nlatter category of continuous-range fixed-point arithmetic\n<a href=\"https://github.com/mizvekov/fp\">[3]</a>\n<a href=\"http://www.codeproject.com/Articles/37636/Fixed-Point-Class\">[6]</a>\n<a href=\"https://github.com/viboes/fixed_point\">[7]</a>. In particular, an\nexisting library proposal, N3352 <a href=\"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html\">[8]</a>,\naims to achieve very similar goals through similar means and warrants\ncloser comparison than N1169.</p>\n<p>N3352 introduces four class templates covering the quadrant of signed\nversus unsigned and fractional versus integer numeric types. It is\nintended to replace built-in types in a wide variety of situations and\naccordingly, is highly compile-time configurable in terms of how\nrounding and overflow are handled. Parameters to these four class\ntemplates include the storage in bits and - for fractional types - the\nresolution.</p>\n<p>The <code>fixed_point</code> class template could probably - with a few caveats -\nbe generated using the two fractional types, <code>nonnegative</code> and\n<code>negatable</code>, replacing the <code>ReprType</code> parameter with the integer bit\ncount of <code>ReprType</code>, specifying <code>fastest</code> for the rounding mode and\nspecifying <code>undefined</code> as the overflow mode.</p>\n<p>However, fixed_point more closely and concisely caters to the needs of\nusers who already use integer types and simply desire a more concise,\nless error-prone form. It more closely follows the four design aims of\nthe library and - it can be argued - more closely follows the spirit\nof the standard in its pursuit of zero-cost abstraction.</p>\n<p>Some aspects of the design of the N3352 API which back up these\nconclusion are that:</p>\n<ul>\n<li>the result of arithmetic operations closely resemble the <code>trunc_</code>\nfunction templates and are potentially more costly at run-time;</li>\n<li>the nature of the range-specifying template parameters - through\ncareful framing in mathematical terms - abstracts away valuable\ninformation regarding machine-critical type size information;</li>\n<li>the breaking up of duties amongst four separate class templates\nintroduces four new concepts and incurs additional mental load for\nrelatively little gain while further detaching the interface from\nvital machine-level details and</li>\n<li>the absence of the most negative number from signed types reduces\nthe capacity of all types by one.</li>\n</ul>\n<p>The added versatility that the N3352 API provides regarding rounding\nand overflow handling are of relatively low priority to users who\nalready bear the scars of battles with raw integer types.\nNevertheless, providing them as options to be turned on or off at\ncompile time is an ideal way to leave the choice in the hands of the\nuser.</p>\n<p>Many high-performance applications - in which fixed-point is of\npotential value - favor run-time checks during development which are\nsubsequently deactivated in production builds. The N3352 interface is\nhighly conducive to this style of development. It is an aim of the\nfixed_point design to be similarly extensible in future revisions.</p>\n<h2 id=\"viii-acknowledgements\">VIII. Acknowledgements</h2>\n<p>Subgroup: Guy Davidson, Michael Wong<br>Contributors: Ed Ainsley, Billy Baker, Lance Dyson, Marco Foco,\nClément Grégoire, Nicolas Guillemot, Matt Kinzelman, Joël Lamotte,\nSean Middleditch, Patrice Roy, Peter Schregle, Ryhor Spivak</p>\n<h2 id=\"ix-references\">IX. References</h2>\n<ol>\n<li>Why Integer Coordinates?, <a href=\"http://www.pathengine.com/Contents/Overview/FundamentalConcepts/WhyIntegerCoordinates/page.php\">http://www.pathengine.com/Contents/Overview/FundamentalConcepts/WhyIntegerCoordinates/page.php</a></li>\n<li>C++ bounded::integer library, <a href=\"http://doublewise.net/c++/bounded/\">http://doublewise.net/c++/bounded/</a></li>\n<li>fp, C++14 Fixed Point Library, <a href=\"https://github.com/mizvekov/fp\">https://github.com/mizvekov/fp</a></li>\n<li>Boost Constrained Value Libarary, <a href=\"http://rk.hekko.pl/constrained_value/\">http://rk.hekko.pl/constrained_value/</a></li>\n<li>N1169, Extensions to support embedded processors, <a href=\"http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf\">http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1169.pdf</a></li>\n<li>fpmath, Fixed Point Math Library, <a href=\"http://www.codeproject.com/Articles/37636/Fixed-Point-Class\">http://www.codeproject.com/Articles/37636/Fixed-Point-Class</a></li>\n<li>Boost fixed_point (proposed), Fixed point integral and fractional types, <a href=\"https://github.com/viboes/fixed_point\">https://github.com/viboes/fixed_point</a></li>\n<li>N3352, C++ Binary Fixed-Point Arithmetic, <a href=\"http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html\">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3352.html</a></li>\n<li>fixed_point, Reference Implementation of P0037, <a href=\"https://github.com/johnmcfarlane/fixed_point\">https://github.com/johnmcfarlane/fixed_point</a></li>\n</ol>\n<h2 id=\"x-appendix-1-reference-implementation\">X. Appendix 1: Reference Implementation</h2>\n<p>An in-development implementation of the fixed_point class template and\nits essential supporting functions and types is available\n<a href=\"https://github.com/johnmcfarlane/fixed_point\">[9]</a>. It includes a\nutility header containing such things as math and trigonometric\nfunctions and a partial <code>numeric_limits</code> specialization. Compile-time\nand run-time tests are included as well as benchmarking support. It is\nthe source of examples and measurements cited here.</p>\n<h2 id=\"xi-appendix-2-performance\">XI. Appendix 2: Performance</h2>\n<p>Despite a focus on usable interface and direct translation from\ninteger-based fixed-point operations, there is an overwhelming\nexpectation that the source code result in minimal instructions and\nclock cycles. A few preliminary numbers are presented to give a very\nearly idea of how the API might perform.</p>\n<p>Some notes:</p>\n<ul>\n<li>A few test functions were run, ranging from single arithmetic\noperations to basic geometric functions, performed against integer,\nfloating-point and fixed-point types for comparison.</li>\n<li><p>Figures were taken from a single CPU, OS and compiler, namely:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>Debian&nbsp;clang&nbsp;version&nbsp;3.5.0-10&nbsp;(tags/RELEASE_350/final)&nbsp;(based&nbsp;on&nbsp;LLVM&nbsp;3.5.0)</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>Target:&nbsp;x86_64-pc-linux-gnu</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>Thread&nbsp;model:&nbsp;posix</span></span></span></div></pre></li>\n<li><p>Fixed inputs were provided to each function, meaning that branch\nprediction rarely fails. Results may also not represent the full\nrange of inputs.</p>\n</li>\n<li>Details of the test harness used can be found in the source\nproject mentioned in Appendix 1;</li>\n<li>Times are in nanoseconds;</li>\n<li>Code has not yet been optimized for performance.</li>\n</ul>\n<h3 id=\"types\">Types</h3>\n<p>Where applicable various combinations of integer, floating-point and\nfixed-point types were tested with the following identifiers:</p>\n<ul>\n<li><code>uint8_t</code>, <code>int8_t</code>, <code>uint16_t</code>, <code>int16_t</code>, <code>uint32_t</code>, <code>int32_t</code>,\n<code>uint64_t</code> and <code>int64_t</code> built-in integer types;</li>\n<li><code>float</code>, <code>double</code> and <code>long double</code> built-in floating-point types;</li>\n<li>s3:4, u4:4, s7:8, u8:8, s15:16, u16:16, s31:32 and u32:32 format\nfixed-point types.</li>\n</ul>\n<h3 id=\"basic-arithmetic\">Basic Arithmetic</h3>\n<p>Plus, minus, multiplication and division were tested in isolation\nusing a number of different numeric types with the following results:</p>\n<p>name    cpu_time<br>add(float)    1.78011<br>add(double)    1.73966<br>add(long double)    3.46011<br>add(u4_4)    1.87726<br>add(s3_4)    1.85051<br>add(u8_8)    1.85417<br>add(s7_8)    1.82057<br>add(u16_16)    1.94194<br>add(s15_16)    1.93463<br>add(u32_32)    1.94674<br>add(s31_32)    1.94446<br>add(int8_t)    2.14857<br>add(uint8_t)    2.12571<br>add(int16_t)    1.9936<br>add(uint16_t)    1.88229<br>add(int32_t)    1.82126<br>add(uint32_t)    1.76<br>add(int64_t)    1.76<br>add(uint64_t)    1.83223<br>sub(float)    1.96617<br>sub(double)    1.98491<br>sub(long double)    3.55474<br>sub(u4_4)    1.77006<br>sub(s3_4)    1.72983<br>sub(u8_8)    1.72983<br>sub(s7_8)    1.72983<br>sub(u16_16)    1.73966<br>sub(s15_16)    1.85051<br>sub(u32_32)    1.88229<br>sub(s31_32)    1.87063<br>sub(int8_t)    1.76<br>sub(uint8_t)    1.74994<br>sub(int16_t)    1.82126<br>sub(uint16_t)    1.83794<br>sub(int32_t)    1.89074<br>sub(uint32_t)    1.85417<br>sub(int64_t)    1.83703<br>sub(uint64_t)    2.04914<br>mul(float)    1.9376<br>mul(double)    1.93097<br>mul(long double)    102.446<br>mul(u4_4)    2.46583<br>mul(s3_4)    2.09189<br>mul(u8_8)    2.08<br>mul(s7_8)    2.18697<br>mul(u16_16)    2.12571<br>mul(s15_16)    2.10789<br>mul(u32_32)    2.10789<br>mul(s31_32)    2.10789<br>mul(int8_t)    1.76<br>mul(uint8_t)    1.78011<br>mul(int16_t)    1.8432<br>mul(uint16_t)    1.76914<br>mul(int32_t)    1.78011<br>mul(uint32_t)    2.19086<br>mul(int64_t)    1.7696<br>mul(uint64_t)    1.79017<br>div(float)    5.12<br>div(double)    7.64343<br>div(long double)    8.304<br>div(u4_4)    3.82171<br>div(s3_4)    3.82171<br>div(u8_8)    3.84<br>div(s7_8)    3.8<br>div(u16_16)    9.152<br>div(s15_16)    11.232<br>div(u32_32)    30.8434<br>div(s31_32)    34<br>div(int8_t)    3.82171<br>div(uint8_t)    3.82171<br>div(int16_t)    3.8<br>div(uint16_t)    3.82171<br>div(int32_t)    3.82171<br>div(uint32_t)    3.81806<br>div(int64_t)    10.2286<br>div(uint64_t)    8.304  </p>\n<p>Among the slowest types are <code>long double</code>. It is likely that they are\nemulated in software. The next slowest operations are fixed-point\nmultiply and divide operations - especially with 64-bit types. This is\nbecause values need to be promoted temporarily to double-width types.\nThis is a known fixed-point technique which inevitably experiences\nslowdown where a 128-bit type is required on a 64-bit system.</p>\n<p>Here is a section of the disassembly of the s15:16 multiply call:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>30:&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;%r14,%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>mov&nbsp;&nbsp;&nbsp;&nbsp;%r15,%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;movslq&nbsp;-0x28(%rbp),%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;movslq&nbsp;-0x30(%rbp),%rcx&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;imul&nbsp;&nbsp;&nbsp;%rax,%rcx&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shr&nbsp;&nbsp;&nbsp;&nbsp;$0x10,%rcx&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;%ecx,-0x38(%rbp)&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;%r12,%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>4c:&nbsp;&nbsp;&nbsp;movzbl&nbsp;(%rbx),%eax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>cmp&nbsp;&nbsp;&nbsp;&nbsp;$0x1,%eax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>↓&nbsp;jne&nbsp;&nbsp;&nbsp;&nbsp;68&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>54:&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;0x8(%rbx),%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>lea&nbsp;&nbsp;&nbsp;&nbsp;0x1(%rax),%rcx&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;%rcx,0x8(%rbx)&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cmp&nbsp;&nbsp;&nbsp;&nbsp;0x38(%rbx),%rax&nbsp;&nbsp;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>↑&nbsp;jb&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;30</span></span></span></div></pre><p>The two 32-bit numbers are multiplied together and the result shifted\ndown - much as it would if raw <code>int</code> values were used. The efficiency\nof this operation varies with the exponent. An exponent of zero should\nmean no shift at all.</p>\n<h3 id=\"3-dimensional-magnitude-squared\">3-Dimensional Magnitude Squared</h3>\n<p>A fast <code>sqrt</code> implementation has not yet been tested with\n<code>fixed_point</code>. (The naive implementation takes over 300ns.) For this\nreason, a magnitude-squared function is measured, combining multiply\nand add operations:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;typename&nbsp;FP&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>constexpr&nbsp;FP&nbsp;magnitude_squared(const&nbsp;FP&nbsp;&amp;&nbsp;x,&nbsp;const&nbsp;FP&nbsp;&amp;&nbsp;y,&nbsp;const&nbsp;FP&nbsp;&amp;&nbsp;z)</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>{</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>return&nbsp;x&nbsp;*&nbsp;x&nbsp;+&nbsp;y&nbsp;*&nbsp;y&nbsp;+&nbsp;z&nbsp;*&nbsp;z;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>}</span></span></span></div></pre><p>Only real number formats are tested:</p>\n<p>float  2.42606<br>double  2.08<br>long double  4.5056<br>s3_4  2.768<br>s7_8  2.77577<br>s15_16  2.752<br>s31_32  4.10331  </p>\n<p>Again, the size of the type seems to have the largest impact.</p>\n<h3 id=\"circle-intersection\">Circle Intersection</h3>\n<p>A similar operation includes a comparison and branch:</p>\n<pre class=\"editor-colors lang-text\"><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>template&nbsp;&lt;typename&nbsp;Real&gt;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>bool&nbsp;circle_intersect_generic(Real&nbsp;x1,&nbsp;Real&nbsp;y1,&nbsp;Real&nbsp;r1,&nbsp;Real&nbsp;x2,&nbsp;Real&nbsp;y2,&nbsp;Real&nbsp;r2)</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>{</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>auto&nbsp;x_diff&nbsp;=&nbsp;x2&nbsp;-&nbsp;x1;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;auto&nbsp;y_diff&nbsp;=&nbsp;y2&nbsp;-&nbsp;y1;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;auto&nbsp;distance_squared&nbsp;=&nbsp;x_diff&nbsp;*&nbsp;x_diff&nbsp;+&nbsp;y_diff&nbsp;*&nbsp;y_diff;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>auto&nbsp;touch_distance&nbsp;=&nbsp;r1&nbsp;+&nbsp;r2;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>&nbsp;&nbsp;&nbsp;&nbsp;auto&nbsp;touch_distance_squared&nbsp;=&nbsp;touch_distance&nbsp;*&nbsp;touch_distance;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;</span></span></div><div class=\"line\"><span class=\"text plain\"><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class=\"meta paragraph text\"><span>return&nbsp;distance_squared&nbsp;&lt;=&nbsp;touch_distance_squared;</span></span></span></div><div class=\"line\"><span class=\"text plain\"><span class=\"meta paragraph text\"><span>}</span></span></span></div></pre><p>float    3.46011<br>double    3.48<br>long double    6.4<br>s3_4    3.88<br>s7_8    4.5312<br>s15_16    3.82171<br>s31_32    5.92  </p>\n<p>Again, fixed-point and native performance are comparable.</p></body>\n</html>\n"
  },
  {
    "path": "Docs/Proposals/rawstorage.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<HTML><HEAD><TITLE>Extending raw_storage_iterator</TITLE>\n<META http-equiv=Content-Type content=\"text/html; charset=windows-1252\">\n</HEAD>\n<BODY>\nLEWG, SG14: D0039R0\n<BR>11-9-2015\n<BR>Brent Friedman \n<br>fourthgeek@gmail.com\n\n\n<H1>Extending raw_storage_iterator</H1>\n\n\n<H2>I. Motivation</H2>\n\n<p>Management of uninitialized memory is an important topic for those implementing containers, allocators, and similar library facilities. This paper seeks to modernize raw storage iterator, bringing important missing features to this utility class.</p>\n\n<H2>II. Summary</H2>\n\n<H3>Move construction</H3>\n<p>raw_storage_iterator lacks support for move construction of elements. Currently users will be faced with the surprising behavior of copy construction in all circumstances.\n<blockquote><code>*it = std::move(x); //copy constructs using x</code></blockquote>\n\n<H3>Factory function</H3>\n<p>raw_storage_iterator requires two template parameters which make its usage fairly verbose. We propose a factory function similar to make_shared for improving readability and making its use less error prone.</p>\n\n<H3>Placement new support</H3>\n<p>The primary use of raw_storage_iterator is to serve as a helper for constructing objects in place. Despite this, it does not support placement new syntax. Support for placement new into a raw storage iterator makes this iterator useful in new contexts.</p>\n\n<H2>III. Discussion</H2>\n<p>Comments at Lenexa stated that raw_storage_iterator is obscure and underused. Fixing these holes should at least open room for this class to be utilized more frequently and to exhibit expected behavior.</p>\n<p>No facilities are provided for conditional move, as with move_if_noexcept. The structure of this class would require an understanding of move_if_noexcept to be built-in to the type system and so seems to have no good avenue for pursuit. Users of raw_storage_iterator should use move_if_noexcept at the callsite as they would with any other iterator:<br>\n<code>\n*it = move_if_noexcept(v);\n</code>\n</p> \n\n<H2>IV. Proposed Text</H2>\n\n<p>Make the following changes in [storage.iterator]: <br>\n\n<blockquote><pre><code>\n  template&lt;class T&gt;\n  auto make_storage_iterator( T&& iterator)\n  {\n    return raw_storage_iterator&lt;std::remove_reference&lt;T&gt;::type, decltype(*iterator)&gt;( std::forward&lt;T&gt;(iterator));\n  }\n\n  template&lt;class T, class U&gt;\n  void* operator new(size_t s, raw_storage_iterator&lt;T,U&gt; it) noexcept\n  {\n    return ::operator new(s, it.base() );\n  }\n\n  template&lt;class T, class U&gt;\n  void operator delete ( void* m, raw_storage_iterator&lt;T,U&gt; it) noexcept\n  {\n    return ::operator delete(m, it.base() );\n  }\n\n</code></pre></blockquote>\n\n<p>Add to raw_storage_iterator:\n\n<blockquote><tt><pre>\n  raw_storage_iterator& operator=(T&& element);\n</pre></tt></blockquote>\n\n<b>Effects:</b> Move-constructs a value from element at the location to which the iterator points.<br>\n<b>Returns:</b> A reference to the iterator. \n</p>\n\n<p>Amend operator=(const T& element) as follows:</p>\n<p>Effects: <u>Copy-c</u>onstructs a value from element ... </p>\n\n</BODY></HTML>"
  },
  {
    "path": "Docs/Proposals/ring_proposal_r5.tex",
    "content": "Document number: P0059R4\nDate: 2017-05-15\nReply-to: Guy Davidson, guy@hatcat.com\nReply-to: Arthur O’Dwyer, arthur.j.odwyer@gmail.com\nAudience: Library Evolution (LEWG), Game dev and low latency (SG14)\nA proposal to add a ring span to the standard library\n0. Contents\nIntroduction\nMotivation\nImpact on the standard\nDesign decisions\nHeader <ring_span> synopsis\n5.1 Function specifications: *_popper\n5.2 Function specifications: ring_span\nSample use\nFuture work\nAcknowledgements\n1. Introduction\nThis proposal introduces a ring to the standard library operating on a span, named ring_span.  The ring_span offers similar facilities to std::queue with the additional feature of storing the elements in contiguous memory and being of a fixed size.  It is an update to P0059R2 to withdraw the addition of a concurrent ring span, at the request of SG1, and to remove iterator semantics, which are considered inappropriate for containers of unowned objects, at the request of LEWG.  The authors seek feedback on the design of the ring before submitting wording for the standard.\n2. Motivation\nQueues are widely used containers for collecting data prior to processing in order of entry to the queue (first in, first out).  The std::queue container adaptor acts as a wrapper to an underlying container, typically std::deque or std::list.  These containers are not of a fixed size and may grow as they fill, which means that each item that is added to a std::queue may prompt an allocation, which will lead to memory fragmentation.  The ring_span operates on elements in contiguous non-owned memory, so memory allocation is eliminated.  The most common uses for the ring_span would be:\nStoring the last n events for later recovery\nCommunicating between threads in an allocation-constrained environment\nBoth of these use cases demand a single producer and a single consumer of elements.\n3. Impact on the standard\nThis proposal is a pure library extension.  It does not require changes to any standard classes, functions or headers.\n4. Design decisions\nNaming\nIn an earlier version of this paper the name ring_buffer was proposed, but given the new implementation the proposed name is ring_span.  The name ring still remains the preferred choice of the authors.\nLook like std::queue\nThere is already an object that offers FIFO support: the std::queue container.  The queue grows to accommodate new entries, allocating new memory as necessary.  The ring interface can therefore be similar to that of the queue with the addition of try_push, try_emplace and try_pop functions: these must now fail if they are called when the ring is full (or empty in the case of try_pop), and should therefore signal that condition by returning a success/fail value.\npush_back and pop_front\nPushing items is a simple matter of assigning to a pre-existing element. The user can decide what to do on filling up the ring: for the synchronous ring it is possible to overwrite unpopped items, which would be desirable for the use case of storing the last n events for later recovery.\n \nPopping items is a more complicated matter than in other containers.  If an item is popped from a std::queue it is destroyed and the memory is released.  In the case of a ring_span however, it does not own the memory so a different strategy must be pursued.  There are four things that could happen when an object is popped from a ring_span, besides the usual container housekeeping:\nThe object is destroyed via the class destructor and the memory is left in an undefined state.\nThe object is replaced with a default-constructed object.\nThe object is replaced with a copy of a user-specified object.\nThe object is not replaced at all.\n \nThis is a choice that will depend on the type being contained.  For example, if the type is not default-constructible, option 2 is unavailable.  If the type is not assignable, options 2 and 3 are unavailable.  There is no single solution that covers all these situations, so as part of the definition of ring_span a number of pop strategy objects are defined.  A strategy can be chosen at the point of declaration of an instance of a ring_span as a template parameter.\n \nAlthough pop could theoretically safely be called on an empty ring with the implementation supplied below, it should yield undefined behaviour.\n5. Header <ring_span> synopsis\nThis section contains the header declarations.  Example definitions are also provided for clarity and to aid specification of the definitions.\nnamespace std::experimental {\ntemplate <typename T> struct null_popper\n{\n  void operator()(T&) const noexcept;\n};\n \ntemplate <typename T> struct default_popper\n{\n  T operator()(T& t) const;\n};\n \ntemplate <typename T> struct copy_popper\n{\n  explicit copy_popper(T&& t);\n  T operator()(T& t) const;\n  T copy;\n};\n \ntemplate<typename T, class Popper = default_popper<T>>\nclass ring_span\n{\npublic:\n  using type = ring_span<T, Popper>;\n  using size_type = std::size_t;\n  using value_type = T;\n  using pointer = T*;\n  using reference = T&;\n  using const_reference = const T&;\n \n  template <class ContiguousIterator>\n  ring_span(ContiguousIterator begin, ContiguousIterator end,\n            Popper p = Popper()) noexcept;\n \n  template <class ContiguousIterator>\n  ring_span(ContiguousIterator begin, ContiguousIterator end,\n            ContiguousIterator first, size_type size,\n            Popper p = Popper()) noexcept;\n \n  ring_span(ring_span&&) = default;\n  ring_span& operator=(ring_span&&) = default;\n \n  bool empty() const noexcept;\n  bool full() const noexcept;\n  size_type size() const noexcept;\n  size_type capacity() const noexcept;\n \n  reference front() noexcept;\n  const_reference front() const noexcept;\n  reference back() noexcept;\n  const_reference back() const noexcept;\n \n  template<bool b = true,\n           typename = std::enable_if_t<b &&\n                      std::is_copy_assignable<T>::value>>\n  void push_back(const value_type& from_value) \n           noexcept(std::is_nothrow_copy_assignable<T>::value);\n \n  template<bool b = true,\n           typename = std::enable_if_t<b &&\n                      std::is_move_assignable<T>::value>>\n  void push_back(value_type&& from_value) \n           noexcept(std::is_nothrow_move_assignable<T>::value);\n \n  template<class... FromType>\n  void emplace_back(FromType&&... from_value) \n         noexcept(std::is_nothrow_constructible<T, FromType...>::value && \n                  std::is_nothrow_move_assignable<T>::value);\n \n  T pop_front();\n \n  void swap(type& rhs)\n           noexcept (std::is_nothrow_swappable<Popper>::value);\n \n// Example implementation\nprivate:\n  reference at(size_type idx) noexcept;\n  const_reference at(size_type idx) const noexcept;\n  size_type back_idx() const noexcept;\n  void increase_size() noexcept;\n \n  T* m_data;\n  size_type m_size;\n  size_type m_capacity;\n  size_type m_front_idx;\n  Popper m_popper;\n};\n5.1. Function specifications: *_popper\nThe null_popper object does nothing to the item being popped from the ring.\n template <typename T>\n void null_popper::operator()(T&) const noexcept\n {};\n \nThe default_popper object moves the item being popped from the ring into the return value.\n template <typename T>\n T default_popper::operator()(T& t) const\n {\n  return std:move(t);\n }\n \nThe copy_popper object replaces the item being popped from the ring with a copy of an item of the contained type, chosen at the declaration site.\n template <typename T>\n explicit copy_popper::copy_popper(T&& t)\n  : copy(std::move(t))\n {}\n \n template <typename T>\n T copy_popper::operator()(T& t) const\n {\n  T old = std::move(t);\n  t = copy;\n  return old;\n }\n5.2 Function specifications: ring_span\nThe first constructor takes a range delimited by two contiguous iterators and an instance of a popper.  After this constructor is executed, the capacity of the ring is the distance between the two iterators and the size of the ring is its capacity.  A typical implementation would be\ntemplate<typename T, class Popper>\ntemplate<class ContiguousIterator>\nring_span<T, Popper>::ring_span(ContiguousIterator begin, ContiguousIterator end, Popper p) noexcept\n  : m_data(&*begin)\n  , m_size(0)\n  , m_capacity(end - begin)\n  , m_front_idx(0)\n  , m_popper(std::move(p))\n  {}\n \nThe second constructor creates a partially full ring.  It takes a range delimited by two contiguous iterators, a third iterator which points to the oldest item of the ring, a size parameter which indicates how many items are in the ring, and an instance of a popper.  After this constructor is executed, the capacity of the ring is the distance between the first two iterators and the size of the ring is the size parameter.  A typical implementation would be\ntemplate<typename T, class Popper>\ntemplate<class ContiguousIterator>\nring_span<T, Popper>::ring_span(ContiguousIterator begin, ContiguousIterator end, ContiguousIterator first, size_type size, Popper p = Popper()) noexcept\n  : m_data(&*begin)\n  , m_size(size)\n  , m_capacity(end - begin)\n  , m_front_idx(first - begin)\n  , m_popper(std::move(p))\n{}\n \nempty(), full(), size() and capacity() behave as expected.  Typical implementations would be:\ntemplate<typename T, class Popper>\nbool ring_span<T, Popper>::empty() const noexcept\n{ return m_size == 0; }\ntemplate<typename T, class Popper>\nbool ring_span<T, Popper>::full() const noexcept\n{ return m_size == m_capacity; }\ntemplate<typename T, class Popper>\nring_span<T, Popper>::size_type ring_span<T, Popper>::size() const noexcept\n{ return m_size; }\ntemplate<typename T, class Popper>\nring_span<T, Popper>::size_type ring_span<T, Popper>::capacity() const noexcept\n{ return m_capacity; }\n \nfront() and back() return the oldest and newest items in the ring.  Typical implementations would be:\ntemplate<typename T, class Popper>\nring_span<T, Popper>::reference ring_span<T, Popper>::front() noexcept\n{ return *begin(); }\ntemplate<typename T, class Popper>\nring_span<T, Popper>::reference ring_span<T, Popper>::back() noexcept\n{ return *(--end()); }\ntemplate<typename T, class Popper>\nring_span<T, Popper>::const_reference ring_span<T, Popper>::front() const noexcept\n{ return *begin(); }\ntemplate<typename T, class Popper>\nring_span<T, Popper>::const_reference ring_span<T, Popper>::back() const noexcept\n{ return *(--end()); }\n \nThe push_back() functions add an item after the most recently added item.  The emplace_back() function creates an item after the most recently added item.  If the size of the ring equals the capacity of the ring, then the oldest item is replaced.  Otherwise, the size of the ring is increased by one.  Typical implementations would be:\ntemplate<typename T, class Popper>\ntemplate<bool b=true, typename=std::enable_if_t<b && std::is_copy_assignable<T>::value>>\nvoid ring_span<T, Popper>::push_back(const T& value) noexcept(std::is_nothrow_copy_assignable<T>::value)\n{\n  m_data[back_idx()] = value;\n  increase_size();\n}\n \ntemplate<typename T, class Popper>\ntemplate<bool b=true, typename=std::enable_if_t<b && std::is_move_assignable<T>::value>>\nvoid ring_span<T, Popper>::push_back(T&& value) noexcept(std::is_nothrow_move_assignable<T>::value)\n{\n  m_data[back_idx()] = std::move(value);\n  increase_size();\n}\n \ntemplate<typename T, class Popper>\ntemplate<class... FromType>\nvoid ring_span<T, Popper>::emplace_back(FromType&&... from_value)\nnoexcept(std::is_nothrow_constructible<T, FromType...>::value &&\n         std::is_nothrow_move_assignable<T>::value);\n{\n  m_data[back_idx()] = T(std::forward<FromType>(from_value)...);\n  increase_size();\n}\n \nThe pop_front() function checks the size of the ring, asserting if it is zero.  If it is non-zero, it passes a reference to the oldest item to the Popper for transformation, reduces the size and advances the front of the ring.  By returning the item from pop, we are able to contain smart pointers.  A typical implementation might be:\ntemplate<typename T, class Popper>\nauto ring_span<T, Popper>::pop_front()\n{\n  assert(m_size != 0);\n  auto old_front_idx = m_front_idx;\n  m_front_idx = (m_front_idx + 1) % m_capacity;\n  --m_size;\n  return m_popper(m_data[old_front_idx]);\n}\n \nThe swap() function is trivial. A typical implementation might be:\ntemplate<typename T, class Popper>\nvoid ring_span<T, Popper>::swap(ring_span<T, Popper>& rhs) noexcept(std::__is_nothrow_swappable<Popper>::value)\n{\n  using std::swap;\n  swap(m_data, rhs.m_data);\n  swap(m_size, rhs.m_size);\n  swap(m_capacity, rhs.m_capacity);\n  swap(m_front_idx, rhs.m_front_idx);\n  swap(m_popper, rhs.m_popper);\n}\n \nFor the sake of clarity, the private implementation used to describe these functions is as follows:\ntemplate<typename T, class Popper>\nring_span<T, Popper>::reference ring_span<T, Popper>::at(size_type i) noexcept\n{ return m_data[i % m_capacity]; }\n \ntemplate<typename T, class Popper>\nring_span<T, Popper>::const_reference ring_span<T, Popper>::at(size_type i) const noexcept\n{ return m_data[i % m_capacity]; }\n \ntemplate<typename T, class Popper>\nring_span<T, Popper>::size_type ring_span<T, Popper>::back_idx() const noexcept\n{ return (m_front_idx + m_size) % m_capacity; }\n \ntemplate<typename T, class Popper>\nvoid ring_span<T, Popper>::increase_size() noexcept\n{ if (++m_size > m_capacity) { m_size = m_capacity; } }\n6. Sample use\n#include <ring_span>\n#include <cassert>\n \nusing std::experimental::ring_span;\n \nvoid ring_test()\n{\n  std::array<int, 5> A;\n  std::array<int, 5> B;\n \n  ring_span<int> Q(std::begin(A), std::end(A));\n \n  Q.push_back(7);\n  Q.push_back(3);\n  assert(Q.size() == 2);\n  assert(Q.front() == 7);\n \n  Q.pop_front();\n  assert(Q.size() == 1);\n \n  Q.push_back(18);\n  auto Q3 = std::move(Q);\n  assert(Q3.front() == 3);\n  assert(Q3.back() == 18);\n \n  sg14::ring_span<int> Q5(std::move(Q3));\n  assert(Q5.front() == 3);\n  assert(Q5.back() == 18);\n  assert(Q5.size() == 2);\n \n  Q5.pop_front();\n  Q5.pop_front();\n  assert(Q5.empty());\n \n  sg14::ring_span<int> Q6(std::begin(B), std::end(B));\n  Q6.push_back(6);\n  Q6.push_back(7);\n  Q6.push_back(8);\n  Q6.push_back(9);\n  Q6.emplace_back(10);\n  Q6.swap(Q5);\n  assert(Q6.empty());\n  assert(Q5.size() == 5);\n  assert(Q5.front() == 6);\n  assert(Q5.back() == 10);\n \n  puts(\"Ring test completed.\\n\");\n}\n7. Future work\nn3353 describes a proposal for a concurrent queue.  The interface is quite different from ring.  A concurrent ring could be adapted from the interface specified therein should n3353 be accepted into the standard.  Considerable demand has been expressed for such an entity by the embedded development community, but at the presentation of revision 2 of this paper to SG1 such a feature was turned down since it overlapped with n3353.  Feedback from developers in the embedded community suggests that a concurrent queue would not be used in their domain because of the contingent unpredictable memory allocation, and a fixed size container such as this would be preferable, even one with the size as a template parameter.\n \nThe popper class templates are defined at an overly broad scope, rather than in the scope of the ring_span.  However, no way of doing this is immediately apparent, beyond the obvious solution of creating a ring namespace and defining the poppers and the span inside it.  Since this is somewhat counterintuitive in the context of the remainder of the standard library, the authors remain open to suggestions.  If the popper class templates might have use in other container spans, then they could remain in the broader scope.\n \nRequests have been made for a mechanism of providing notification when an item has been pushed. This could be achieved by creating a pusher policy, analogous to the popper objects. If this is deemed valuable then this proposal can be modified accordingly.\n8. Acknowledgements\nThanks to Jonathan Wakely for sprucing up the first draft of the ring interface.\nThanks to the SG14 forum contributors: Nicolas Guillemot, John McFarlane, Scott Wardle, Chris Gascoyne, Matt Newport.\nThanks to the SG14 meeting contributors: Charles Beattie, Brittany Friedman, Billy Baker, Bob, Sean Middleditch, Ville Voutilainen.\nThanks to Michael McLaughlin for commentary on the draft of the text.\nThanks to Lawrence Crowl for pointing me to his paper on concurrent queues, n3353.\nSpecial thanks also to Michael Wong for convening and shepherding SG14.\n"
  },
  {
    "path": "Docs/Proposals/uninitialized.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<HTML><HEAD><TITLE>Extending memory management tools</TITLE>\n<META http-equiv=Content-Type content=\"text/html; charset=windows-1252\">\n</HEAD>\n<BODY>\nLEWG, SG14: D0040R0\n<BR>11-9-2015\n<BR>Brent Friedman <br>fourthgeek@gmail.com\n<H1>Extending memory management tools</H1>\n\n\n<H2>I. Motivation</H2>\n\n<p>When implementing containers that do not rely on standard allocators it is often necessary to manage memory directly. This paper seeks to fill gaps in the standard library's memory management utilities.</p>\n\n<H2>II. Summary</H2>\n\n<p>\nThe function template <code>destroy</code> calls the destructor for specified elements.<br>\nThe function template <code>uninitialized_move</code> performs move construction of elements over a range of memory, similar to <code>uninitialized_copy</code>. <code>uninitialized_move_n</code> is also provided.<br>\nThe function template <code>uninitialized_value_construct</code> performs value-construction of objects over a range of memory.<br>\nThe function template <code>uninitialized_default_construct</code> performs default-construction of objects over a range of memory.<br><br>\n</p>\n<H2>III. Discussion </H2>\n<p>Interface changes proposed in the \"range\" proposals should be mirrored if both are accepted.</p>\n\n<p><code>destroy</code> first appeared in SGI's Standard Template Library. It is not known by the author why this algorithm was not inherited into the C++ Standard Library in its initial stages. Several responses have preferred that the algorithm be called <code>destruct</code>, however, <code>destroy</code> maintains convention with SGI and appears to be considered more appropriate use of English.</p>\n<p>\nIt is not possible to implement the \"no effects\" policy for <code>destroy</code> so it is specifically excluded from that rule.\n</p>\n<p>\nThe names <code>uninitialized_value_construct</code> and <code>uninitialized_default_construct</code> explicitly reflect their effects but do not clearly match terminology in other standard library functions. Proposal N3939 has chosen the _noinit suffix to denote value vs. default construction. If LEWG prefers this direction then the algorithms could be renamed to <code>uninitialized_construct</code> and <code>uninitialized_construct_noinit</code>.</p>\n\n<p>\nSome concern is raised about exception handling with respect to <code>uninitialized_move</code>. If a move-constructor throws, moved-from objects may be left in a poorly defined state. Given that algorithm <code>move</code> has no special support for this case, it is believed that throwing constructors for this algorithm can be treated similarly. It is believed that the \"no effects\" wording of this section is sufficient as is.<br>\nAn additional algorithm, <code>uninitialized_move_if_noexcept</code>, could be considered as a resolution to this concern. Given that there is currently no range-based <code>move_if_noexcept</code> algorithm, such a solution is not considered here. It is however trivial to implement such an algorithm -- simply forwarding to copy or move as appropriate. The same would hold true for uninitialized algorithms.\n</p>\n\n<p>\n\n</p>\n<H2>IV. Proposed Text</H2>\n\n<p>Make the following changes in [specialized.algorithm]: <br>\n<p>Modify: In the algorithm<u>s</u> uninitialized_copy <u>and uninitialized_move</u>, the template parameter InputIterator is required...</p>\n<p>Modify: In the following algorithms <u> other than destroy</u>, if an exception is thrown there are no effects.</p>\nAdd:\n<blockquote><pre><code>\n\ttemplate&lt;class ForwardIterator&gt;\n\tvoid destroy(ForwardIterator begin, ForwardIterator end);\n\t\n\t<i>Effects:</i>\n\t\ttypedef typename iterator_traits&lt;ForwardIterator&gt;::value_type __t;\n\t\twhile (begin != end)\n\t\t{\n\t\t\tbegin-&gt;~__t();\n\t\t\t++begin;\n\t\t}\n\n\t\t\n\ttemplate &lt;class InputIterator, class ForwardIterator&gt;\n\tForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result);\n\n\t<i>Effects:</i>\n\t\tfor (; first != last; ++result, ++first)\n\t\t\t::new (static_cast&lt;void*&gt;(addressof(*result)))\n\t\t\t\ttypename iterator_traits&lt;ForwardIterator&gt;::value_type(std::move(*first));\n\t\treturn result;\n\t\t\n\ttemplate &lt;class InputIterator, class ForwardIterator&gt;\n\tForwardIterator uninitialized_move_n(InputIterator first, size_t count, ForwardIterator result);\t\n\t\n\t<i>Effects:</i>\n\t\tfor ( ; count&gt;0; ++result, ++first, --count)\n\t\t\t::new (static_cast&lt;void*&gt;(addressof(*result)))\n\t\t\t\ttypename iterator_traits&lt;ForwardIterator&gt;::value_type(std::move(*first));\n\t\treturn result;\n\t\n\ttemplate&lt;class ForwardIterator&gt;\n\tFwdIt uninitialized_value_construct(ForwardIterator first, ForwardIterator last);\n\t\n\t<i>Effects:</i>\n\t\tfor (; first != last; ++first)\n\t\t\t::new (static_cast&lt;void*&gt;(addressof(*first)))\n\t\t\t\ttypename iterator_traits&lt;ForwardIterator&gt;::value_type();\n\t\treturn first;\n\t\n\ttemplate&lt;class ForwardIterator&gt;\n\tFwdIt uninitialized_default_construct(ForwardIterator first, ForwardIterator last);\n\t\n\t<i>Effects:</i>\n\t\tfor (; first != last; ++first)\n\t\t\t::new (static_cast&lt;void*&gt;(addressof(*first)))\n\t\t\t\ttypename iterator_traits&lt;ForwardIterator&gt;::value_type;\n\t\treturn first;\n\t\n</code></pre></blockquote>\n\n</BODY></HTML>"
  },
  {
    "path": "Docs/Proposals/unstable_remove.html",
    "content": "LEWG, SG14: D0041R0<br>\n11-9-2015<br>\nBrent Friedman<br>\nfourthgeek@gmail.com\n<h1>Unstable remove algorithms</h1>\n<h2>I. Summary</h2>\n<p>This proposal covers new algorithms for removing elements from a range without the stability guarantees of existing algorithms.</p>\n\n\n<h2>II. Motivation</h2>\n<p>The stability requirements of existing remove algorithms impose overhead on users, especially for types which are expensive to move. For cases where element order need not be preserved, an unstable algorithm can prove beneficial for efficiency. unstable_remove has complexity proportional to the number of elements to be removed, whereas stable removal has complexity proportional to the number of elements that need to be moved into the \"holes\".</p>\n\n\n<p>The following URL demonstrates generated assembly for implementations of similar algorithms:<br>\n<A href=\"https://goo.gl/xfCxzL\">https://goo.gl/xfCxzL</A></p>\n\n<p>It is observed that unstable_remove generates less code than remove_if and partition. In particular we may note that swapping two elements, as with partition, can be much more expensive than move-assignment.</p>\n\n<p>The following URL demonstrates performance tests for these same implementations:<br>\n<a href=\"https://github.com/WG21-SG14/SG14\">https://github.com/WG21-SG14/SG14</a></p>\n\n<p>It is observed that unstable_remove_if can outperform both remove_if and partition by a measurable degree.</p>\n\n<p>These examples suggest that unstable_remove algorithms can be both smaller and faster than existing solutions.</p>\n\n<h2>III. Additional work</h2>\n<p>Algorithmic changes proposed in the \"range\" proposals should be applied to these algorithms if both are accepted.</p>\n<p>The value of unstable_remove can be applied to containers directly, implying unstable_erase* algorithms or member functions. The following pseudocode signatures are informally provided here for reference and discussion but are not proposed in this paper.</p>\n<p><pre><code>\n//1.\nIt unstable_erase(Cont& C, It at);\n//2.\nIt unstable_erase(Cont& C, It begin, It end);\n//3.\nIt unstable_erase_if(Cont& C, Pred p); //unstable_remove_if + erase\n//4.\nIt unstable_erase(Cont& C, const T& value); //unstable_remove + erase\n\n</code></pre></p>\n\n<h2>IV. Discussion</h2>\n<p>Some skepticism is levied against the utility of creating unstable variants for all erase and remove features. The cost and value of each variant may be difficult to evaluate individually, which is why this proposal covers only the most fundamental functionality of unstable_remove and unstable_remove_if. This author does believe that all removal and erasure features with stability guarantees should have variants without those stability guarantees.</p>\n<p>Some see unstable container erasure as even more important than unstable_remove. It is in the author's opinion that unstable_remove algorithms remain independently useful in many contexts (such as fixed sized containers) and constitute more fundamental functionality than erasure.</p>\n<p>For linked lists, the best efficiency guarantees for unstable_erase are provided by forwarding to existing, stable erase functions. It is believed that no additional wording for this case would be necessary, but some clarification may be desirable.</p>\n<p>It is noted that for <code>vector&lt;int&gt; x</code>, and the following code samples,<br>\n<pre><code>\nx.unstable_erase( unstable_remove( x.begin(), x.end(), 0), x.end()); //A.\nx.erase( unstable_remove(x.begin(), x.end(), 0), x.end()); //B.\n</code></pre><br>A provides no efficiency benefits over B. unstable_erase provides benefits only when the range to be removed occurs within the middle of the container. This may lead to some confusion among users, though A and B would provide the same results.</p>\n\n<p></p>\n<p>\n<h2>V. Proposed Wording</h2>\n<p>In [alg.remove]<br>\n\nFirst section:<br>\n<code>\ntemplate&lt;class ForwardIterator, class T&gt;\nForwardIterator unstable_remove(ForwardIterator first, ForwardIterator last,\nconst T& value); <br>\ntemplate&lt;class ForwardIterator, class Predicate&gt;\nForwardIterator unstable_remove_if(ForwardIterator first, ForwardIterator last,Predicate pred); \n\n</code>\n<br><br>\nRemarks (remove, remove_if): Stable <br>\n</p>\n\n<p>\n\nSecond section:<br>\n<code>\ntemplate&lt;class InputIterator, class OutputIterator, class T&gt;\nOutputIterator\nunstable_remove_copy(InputIterator first, InputIterator last,\nOutputIterator result, const T& value);<br>\n\ntemplate&lt;class InputIterator, class OutputIterator, class Predicate&gt;\nOutputIterator\nunstable_remove_copy_if(InputIterator first, InputIterator last,\nOutputIterator result, Predicate pred);\n</code>\n\n<br><br>\nRemarks (remove_copy, remove_copy_if): Stable<br>\n\n</p>"
  },
  {
    "path": "Docs/fixed_point.md",
    "content": "# Fixed-Point Real Numbers\n\n[John McFarlane](https://groups.google.com/a/isocpp.org/forum/#!profile/sg14/APn2wQdoie4ys78eOuHNF35KKYtO4LHy0d1z8jGXJ0cr5tzmqGbDbD7BFUzrqWrU7tJiBi_UnRqo)\n\nSupport for fixed-point arithmetic in the standard library is\nproposed. It is described in paper,\n[LEWG, EWG, SG14, SG6: D0037](Proposals/Fixed_Point_Library_Proposal.md).\nAn [experimental implementation](https://github.com/johnmcfarlane/fixed_point)\nis in development. Potential users are invited to provide feedback on\nthe [SG14 forum](https://groups.google.com/a/isocpp.org/forum/#!forum/sg14).\n"
  },
  {
    "path": "Docs/plf_licensing.txt",
    "content": "All plf:: modules are provided under a zlib license:\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any damages\narising from the use of this software.\n\nPermission is granted to anyone to use this software for any purpose,\nincluding commercial applications, and to alter it and redistribute it\nfreely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must not\n   claim that you wrote the original software. If you use this software\n   in a product, an acknowledgement in the product documentation would be\n   appreciated but is not required.\n2. Altered source versions must be plainly marked as such, and must not be\n   misrepresented as being the original software.\n3. This notice may not be removed or altered from any source distribution.\n\nCopyright (c) 2015 Matthew Bentley\n"
  },
  {
    "path": "README.md",
    "content": "# SG14\n[![Build Status](https://travis-ci.org/WG21-SG14/SG14.svg?branch=master)](https://travis-ci.org/WG21-SG14/SG14)\n\nA library for Study Group 14 of Working Group 21 (C++)\n\n/docs - Documentation for implementations without proposals, or supplementary documentation which does not easily fit within a proposal.\n\n/docs/proposals - C++ standard proposals.\n\n/SG14 - Source files for implementations.\n\n/SG14_test - Individual tests for implementations.\n\nhttp://lists.isocpp.org/mailman/listinfo.cgi/sg14 for more information\n\n## Build Instructions\nClone the repo. Navigate to the folder in your favorite terminal.\n\n`mkdir build && cd build`\n\n### Windows\n`cmake .. -A x64 && cmake --build . && bin\\sg14_tests.exe`\n\n### Unixes\n`cmake .. && cmake --build . && ./bin/sg14_tests`\n\n### Alternatively\n`cd SG14_test && g++ -std=c++14 -DTEST_MAIN -I../SG14 whatever_test.cpp && ./a.out`\n"
  },
  {
    "path": "SG14/algorithm_ext.h",
    "content": "#pragma once\n\n#include <algorithm>\n#include <iterator>\n#include <memory>\n#include <utility>\n\nnamespace stdext\n{\n\ttemplate<class ForwardIterator>\n\tvoid destruct(ForwardIterator begin, ForwardIterator end)\n\t{\n\t\ttypedef typename std::iterator_traits<ForwardIterator>::value_type _T;\n\t\twhile (begin != end)\n\t\t{\n\t\t\tbegin->~_T();\n\t\t\t++begin;\n\t\t}\n\t}\n\n\n\ttemplate<class SrcIt, class Sentinel, class FwdIt>\n\tFwdIt uninitialized_move(SrcIt SrcBegin, Sentinel SrcEnd, FwdIt Dst)\n\t{\n\t\tFwdIt current = Dst;\n\t\ttry\n\t\t{\n\t\t\twhile (SrcBegin != SrcEnd)\n\t\t\t{\n\t\t\t\t::new (static_cast<void*>(std::addressof(*current))) typename std::iterator_traits<FwdIt>::value_type(std::move(*SrcBegin));\n\t\t\t\t++current;\n\t\t\t\t++SrcBegin;\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tdestruct(Dst, current);\n\t\t\tthrow;\n\t\t}\n\t}\n\n\ttemplate<class FwdIt, class Sentinel>\n\tFwdIt uninitialized_value_construct(FwdIt first, Sentinel last)\n\t{\n\t\tFwdIt current = first;\n\t\ttry\n\t\t{\n\t\t\twhile (current != last)\n\t\t\t{\n\t\t\t\t::new (static_cast<void*>(std::addressof(*current))) typename std::iterator_traits<FwdIt>::value_type();\n\t\t\t\t++current;\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tdestruct(first, current);\n\t\t\tthrow;\n\t\t}\n\t}\n\n\ttemplate<class FwdIt, class Sentinel>\n\tFwdIt uninitialized_default_construct(FwdIt first, Sentinel last)\n\t{\n\t\tFwdIt current = first;\n\t\ttry\n\t\t{\n\t\t\twhile (current != last)\n\t\t\t{\n\t\t\t\t::new (static_cast<void*>(std::addressof(*current))) typename std::iterator_traits<FwdIt>::value_type;\n\t\t\t\t++current;\n\t\t\t}\n\t\t\treturn current;\n\t\t}\n\t\tcatch (...)\n\t\t{\n\t\t\tdestruct(first, current);\n\t\t\tthrow;\n\t\t}\n\t}\n\n\ttemplate<class BidirIt, class UnaryPredicate>\n\tBidirIt unstable_remove_if(BidirIt first, BidirIt last, UnaryPredicate p)\n\t{\n\t\twhile (true) {\n\t\t\t// Find the first instance of \"p\"...\n\t\t\twhile (true) {\n\t\t\t\tif (first == last) {\n\t\t\t\t\treturn first;\n\t\t\t\t}\n\t\t\t\tif (p(*first)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t++first;\n\t\t\t}\n\t\t\t// ...and the last instance of \"not p\"...\n\t\t\twhile (true) {\n\t\t\t\t--last;\n\t\t\t\tif (first == last) {\n\t\t\t\t\treturn first;\n\t\t\t\t}\n\t\t\t\tif (!p(*last)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// ...and move the latter over top of the former.\n\t\t\t*first = std::move(*last);\n\t\t\t++first;\n\t\t}\n\t}\n\n\ttemplate<class BidirIt, class Val>\n\tBidirIt unstable_remove(BidirIt first, BidirIt last, const Val& v)\n\t{\n\t\twhile (true) {\n\t\t\t// Find the first instance of \"v\"...\n\t\t\twhile (true) {\n\t\t\t\tif (first == last) {\n\t\t\t\t\treturn first;\n\t\t\t\t}\n\t\t\t\tif (*first == v) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t++first;\n\t\t\t}\n\t\t\t// ...and the last instance of \"not v\"...\n\t\t\twhile (true) {\n\t\t\t\t--last;\n\t\t\t\tif (first == last) {\n\t\t\t\t\treturn first;\n\t\t\t\t}\n\t\t\t\tif (!(*last == v)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// ...and move the latter over top of the former.\n\t\t\t*first = std::move(*last);\n\t\t\t++first;\n\t\t}\n\t}\n\n\n\t//this exists as a point of reference for providing a stable comparison vs unstable_remove_if\n\ttemplate<class BidirIt, class UnaryPredicate>\n\tBidirIt partition(BidirIt first, BidirIt last, UnaryPredicate p)\n\t{\n\t\twhile (true) {\n\t\t\twhile ((first != last) && p(*first)) {\n\t\t\t\t++first;\n\t\t\t}\n\t\t\tif (first == last) break;\n\t\t\t--last;\n\t\t\twhile ((first != last) && !p(*last)) {\n\t\t\t\t--last;\n\t\t\t}\n\t\t\tif (first == last) break;\n\t\t\tstd::iter_swap(first, last);\n\t\t\t++first;\n\t\t}\n\t\treturn first;\n\t}\n\n\t//this exists as a point of reference for providing a stable comparison vs unstable_remove_if\n\ttemplate<class ForwardIt, class UnaryPredicate>\n\tForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)\n\t{\n\t\tfirst = std::find_if(first, last, p);\n\t\tif (first != last) {\n\t\t\tfor (ForwardIt i = first; ++i != last; ) {\n\t\t\t\tif (!p(*i)) {\n\t\t\t\t\t*first = std::move(*i);\n\t\t\t\t\t++first;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn first;\n\t}\n}\n"
  },
  {
    "path": "SG14/flat_map.h",
    "content": "/*\n * Boost Software License - Version 1.0 - August 17th, 2003\n *\n * Permission is hereby granted, free of charge, to any person or organization\n * obtaining a copy of the software and accompanying documentation covered by\n * this license (the \"Software\") to use, reproduce, display, distribute,\n * execute, and transmit the Software, and to prepare derivative works of the\n * Software, and to permit third-parties to whom the Software is furnished to\n * do so, all subject to the following:\n *\n * The copyright notices in the Software and this entire statement, including\n * the above license grant, this restriction and the following disclaimer,\n * must be included in all copies of the Software, in whole or in part, and\n * all derivative works of the Software, unless such copies or derivative\n * works are solely in the form of machine-executable object code generated by\n * a source language processor.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n */\n\n#pragma once\n\n// This is an implementation of the proposed \"std::flat_map\" as specified in\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0429r6.pdf\n\n#include <stddef.h>\n#include <algorithm>\n#include <functional>\n#include <initializer_list>\n#include <iterator>\n#include <vector>\n\nnamespace stdext {\n\nnamespace flatmap_detail {\n    template<class T, class = void> struct qualifies_as_range : std::false_type {};\n    template<class T> struct qualifies_as_range<T, decltype(\n        std::begin( std::declval<T()>()() ), void(),\n        std::end( std::declval<T()>()() ), void()\n    )> : std::true_type {};\n\n    template<class It>\n    using is_random_access_iterator = std::is_convertible<\n        typename std::iterator_traits<It>::iterator_category,\n        std::random_access_iterator_tag\n    >;\n\n    template<int I> struct priority_tag : priority_tag<I-1> {};\n    template<> struct priority_tag<0> {};\n\n    // As proposed in P0591R4. Guaranteed copy elision makes this do the right thing.\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        std::uses_allocator<T, Alloc>::value && std::is_constructible<T, std::allocator_arg_t, const Alloc&, Args&&...>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<3>, const Alloc& alloc, Args&&... args) {\n        return T(std::allocator_arg, alloc, static_cast<Args&&>(args)...);\n    }\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        std::uses_allocator<T, Alloc>::value && std::is_constructible<T, Args&&..., const Alloc&>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<2>, const Alloc& alloc, Args&&... args) {\n        return T(static_cast<Args&&>(args)..., alloc);\n    }\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        !std::uses_allocator<T, Alloc>::value && std::is_constructible<T, Args&&...>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<1>, const Alloc&, Args&&... args) {\n        return T(static_cast<Args&&>(args)...);\n    }\n    template<class T, class Alloc, class... Args>\n    T make_obj_using_allocator_(priority_tag<0>, const Alloc&, Args&&...) {\n        static_assert(sizeof(T)==0, \"this request for uses-allocator construction is ill-formed\");\n    }\n    template<class T, class Alloc, class... Args>\n    T make_obj_using_allocator(const Alloc& alloc, Args&&... args) {\n        return make_obj_using_allocator_<T>(priority_tag<3>(), alloc, static_cast<Args&&>(args)...);\n    }\n\n    template<class Container>\n    using cont_key_type = typename std::remove_const<typename Container::value_type::first_type>::type;\n\n    template<class Container>\n    using cont_mapped_type = typename Container::value_type::second_type;\n\n    template<class InputIterator>\n    using iter_key_type = typename std::remove_const<typename std::iterator_traits<InputIterator>::value_type::first_type>::type;\n\n    template<class InputIterator>\n    using iter_mapped_type = typename std::iterator_traits<InputIterator>::value_type::second_type;\n\n    template<class...> using void_t = void;\n\n    template<class A, class = void>\n    struct qualifies_as_allocator : std::false_type {};\n    template<class A>\n    struct qualifies_as_allocator<A, void_t<\n        typename A::value_type,\n        decltype(std::declval<A&>().allocate(size_t{}))\n    >> : std::true_type {};\n\n    template<class It>\n    using qualifies_as_input_iterator = std::integral_constant<bool, !std::is_integral<It>::value>;\n\n    template<class... Its>\n    void swap_together(size_t i, size_t j, Its... its)\n    {\n        using std::swap;\n        int dummy[] = {\n            0,\n            (std::iter_swap(its + i, its + j), 0) ...\n        };\n        (void)dummy;\n    }\n\n    template<class Predicate, class Head, class... Rest>\n    size_t partition_together(Predicate& pred, size_t left, size_t right, Head head, const Rest... rest) {\n        while (left < right) {\n            while (left != right && pred(*(head + left))) ++left;\n            while (left != right && !pred(*(head + (right-1)))) --right;\n            if (left + 1 < right) {\n                flatmap_detail::swap_together(left, right-1, head, rest...);\n                ++left;\n                --right;\n            }\n        }\n        return right;\n    }\n\n    template<class Compare, class Head, class... Rest>\n    void sort_together(Compare& less, size_t left, size_t right, Head head, Rest... rest) {\n        if (right - left >= 3) {\n            size_t pivot_idx = left + (right - left) / 2;\n            // Swap the pivot element all the way to the right.\n            if (pivot_idx != right - 1) {\n                flatmap_detail::swap_together(pivot_idx, right-1, head, rest...);\n            }\n            const auto& pivot_elt = *(head + (right-1));\n            auto less_than_pivot = [&](const auto& x) -> bool {\n                return less(x, pivot_elt);\n            };\n            size_t correct_pivot_idx = flatmap_detail::partition_together(less_than_pivot, left, right-1, head, rest...);\n            if (correct_pivot_idx != right-1) {\n                flatmap_detail::swap_together(correct_pivot_idx, right-1, head, rest...);\n            }\n            flatmap_detail::sort_together(less, left, correct_pivot_idx, head, rest...);\n            flatmap_detail::sort_together(less, correct_pivot_idx+1, right, head, rest...);\n        } else if (right - left == 2) {\n            if (less(*(head + left), *(head + (left+1)))) {\n                // nothing to do\n            } else {\n                flatmap_detail::swap_together(left, left+1, head, rest...);\n            }\n        }\n    }\n\n    template<class Compare, class Head, class... Rest>\n    void sort_together(Compare less, Head& head, Rest&... rest) {\n        flatmap_detail::sort_together(less, 0, head.size(), head.begin(), rest.begin()...);\n    }\n\n    template<class It, class It2, class Compare>\n    It unique_helper(It first, It last, It2 mapped, Compare& compare) {\n        It dfirst = first;\n        It2 dmapped = mapped;\n        while (first != last) {\n            It next = first;\n            ++next;\n            if ((next != last) && !bool(compare(*first, *next))) {\n                // \"next\" is a duplicate of \"first\", so do not preserve \"first\"\n            } else {\n                // do preserve \"first\"\n                if (first != dfirst) {\n                    *dfirst = std::move(*first);\n                    *dmapped = std::move(*mapped);\n                }\n                ++dfirst;\n                ++dmapped;\n            }\n            first = next;\n            ++mapped;\n        }\n        return dfirst;\n    }\n\n    template<class, class> class iter;\n    template<class K, class V> iter<K, V> make_iterator(K, V);\n\n    template<class Reference>\n    struct arrow_proxy {\n        Reference *operator->() { return std::addressof(data_); }\n\n        template<class, class> friend class iter;\n\n        Reference data_;\n    };\n\n    template<class KeyIt, class MappedIt>\n    class iter {\n    public:\n        using difference_type = ptrdiff_t;\n        using value_type = std::pair<const typename std::iterator_traits<KeyIt>::value_type, typename std::iterator_traits<MappedIt>::value_type>;\n        using reference = std::pair<typename std::iterator_traits<KeyIt>::reference, typename std::iterator_traits<MappedIt>::reference>;\n        using pointer = arrow_proxy<reference>;\n        using iterator_category = std::random_access_iterator_tag;\n\n        iter() = default;\n        iter(iter&&) = default;\n        iter(const iter&) = default;\n        iter& operator=(iter&&) = default;\n        iter& operator=(const iter&) = default;\n        ~iter() = default;\n\n        // This is the iterator-to-const_iterator implicit conversion.\n        template<class CK, class CM,\n                 class = typename std::enable_if<std::is_convertible<CK, KeyIt>::value>::type,\n                 class = typename std::enable_if<std::is_convertible<CM, MappedIt>::value>::type>\n        iter(const iter<CK, CM>& other) : kit_(other.private_impl_getkey()), vit_(other.private_impl_getmapped()) {}\n\n        reference operator*() const {\n            return reference{*kit_, *vit_};\n        }\n\n        pointer operator->() const {\n            return arrow_proxy<reference>{reference{*kit_, *vit_}};\n        }\n\n        iter& operator++() { ++kit_; ++vit_; return *this; }\n        iter& operator--() { --kit_; --vit_; return *this; }\n        iter operator++(int) { iter result(*this); ++*this; return result; }\n        iter operator--(int) { iter result(*this); --*this; return result; }\n        iter& operator+=(ptrdiff_t n) { kit_ += n; vit_ += n; return *this; }\n        iter& operator-=(ptrdiff_t n) { kit_ -= n; vit_ -= n; return *this; }\n        reference operator[](ptrdiff_t n) const { return *(*this + n); }\n        friend iter operator+(iter it, ptrdiff_t n) { it += n; return it; }\n        friend iter operator+(ptrdiff_t n, iter it) { it += n; return it; }\n        friend iter operator-(iter it, ptrdiff_t n) { it -= n; return it; }\n        friend ptrdiff_t operator-(const iter& it, const iter& jt) { return ptrdiff_t(it.kit_ - jt.kit_); }\n        friend bool operator==(const iter& a, const iter& b) { return a.kit_ == b.kit_; }\n        friend bool operator!=(const iter& a, const iter& b) { return !(a.kit_ == b.kit_); }\n        friend bool operator<(const iter& a, const iter& b) { return a.kit_ < b.kit_; }\n        friend bool operator<=(const iter& a, const iter& b) { return !(b.kit_ < a.kit_); }\n        friend bool operator>(const iter& a, const iter& b) { return b.kit_ < a.kit_; }\n        friend bool operator>=(const iter& a, const iter& b) { return !(a.kit_ < b.kit_); }\n\n        KeyIt private_impl_getkey() const { return kit_; }\n        MappedIt private_impl_getmapped() const { return vit_; }\n\n    private:\n        template<class K, class V>\n        friend iter<K, V> make_iterator(K, V);\n\n        explicit iter(KeyIt&& kit, MappedIt&& vit)\n            : kit_(static_cast<KeyIt&&>(kit)), vit_(static_cast<MappedIt&&>(vit)) {}\n        KeyIt kit_;\n        MappedIt vit_;\n    };\n\n    template<class K, class V>\n    iter<K, V> make_iterator(K kit, V vit) {\n        return iter<K, V>(static_cast<K&&>(kit), static_cast<V&&>(vit));\n    }\n\n} // namespace flatmap_detail\n\n#ifndef STDEXT_HAS_SORTED_UNIQUE\n#define STDEXT_HAS_SORTED_UNIQUE\n\nstruct sorted_unique_t { explicit sorted_unique_t() = default; };\n\n#if defined(__cpp_inline_variables)\ninline\n#endif\nconstexpr sorted_unique_t sorted_unique {};\n\n#endif // STDEXT_HAS_SORTED_UNIQUE\n\ntemplate<\n    class Key,\n    class Mapped,\n    class Compare = std::less<Key>,\n    class KeyContainer = std::vector<Key>,\n    class MappedContainer = std::vector<Mapped>\n>\nclass flat_map {\n    static_assert(flatmap_detail::is_random_access_iterator<typename KeyContainer::iterator>::value, \"\");\n    static_assert(flatmap_detail::is_random_access_iterator<typename MappedContainer::iterator>::value, \"\");\n    static_assert(std::is_same<Key, typename KeyContainer::value_type>::value, \"\");\n    static_assert(std::is_same<Mapped, typename MappedContainer::value_type>::value, \"\");\n    static_assert(!std::is_const<KeyContainer>::value && !std::is_const<Key>::value, \"\");\n    static_assert(!std::is_const<MappedContainer>::value && !std::is_const<Mapped>::value, \"\");\n    static_assert(!std::is_reference<KeyContainer>::value && !std::is_reference<Key>::value, \"\");\n    static_assert(!std::is_reference<MappedContainer>::value && !std::is_reference<Mapped>::value, \"\");\n    static_assert(std::is_convertible<decltype(std::declval<const Compare&>()(std::declval<const Key&>(), std::declval<const Key&>())), bool>::value, \"\");\n#if defined(__cpp_lib_is_swappable)\n    static_assert(std::is_nothrow_swappable<KeyContainer>::value, \"\");\n    static_assert(std::is_nothrow_swappable<MappedContainer>::value, \"\");\n#endif\npublic:\n    using key_type = Key;\n    using mapped_type = Mapped;\n    using value_type = std::pair<const Key, Mapped>;\n    using key_compare = Compare;\n    using const_key_reference = typename KeyContainer::const_reference;\n    using mapped_reference = typename MappedContainer::reference;\n    using const_mapped_reference = typename MappedContainer::const_reference;\n    using reference = std::pair<const_key_reference, mapped_reference>;\n    using const_reference = std::pair<const_key_reference, const_mapped_reference>;\n    using size_type = size_t; // TODO: this should be KeyContainer::size_type\n    using difference_type = ptrdiff_t; // TODO: this should be KeyContainer::difference_type\n    using iterator = flatmap_detail::iter<typename KeyContainer::const_iterator, typename MappedContainer::iterator>;\n    using const_iterator = flatmap_detail::iter<typename KeyContainer::const_iterator, typename MappedContainer::const_iterator>;\n    using reverse_iterator = std::reverse_iterator<iterator>;\n    using const_reverse_iterator = std::reverse_iterator<const_iterator>;\n    using key_container_type = KeyContainer;\n    using mapped_container_type = MappedContainer;\n\n    class value_compare {\n        friend class flat_map;\n    protected:\n        // TODO: this should be private\n        Compare comp;\n        // TODO: this constructor should be explicit\n        value_compare(Compare c): comp(c) {}\n    public:\n        bool operator()(const_reference x, const_reference y) const {\n            return comp(x.first, y.first);\n        }\n    };\n\n    struct containers {\n        KeyContainer keys;\n        MappedContainer values;\n    };\n\n// =========================================================== CONSTRUCTORS\n// This is all one massive overload set!\n\n    flat_map() : flat_map(Compare()) {}\n\n    flat_map(KeyContainer keys, MappedContainer values)\n        : c_{static_cast<KeyContainer&&>(keys), static_cast<MappedContainer&&>(values)}, compare_()\n    {\n        this->sort_and_unique_impl();\n    }\n\n    // TODO: surely this should use uses-allocator construction\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(KeyContainer keys, MappedContainer values, const Alloc& a)\n        : flat_map(KeyContainer(static_cast<KeyContainer&&>(keys), a), MappedContainer(static_cast<MappedContainer&&>(values), a)) {}\n\n    template<class Container,\n             typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value, int>::type = 0>\n    explicit flat_map(const Container& cont)\n        : flat_map(std::begin(cont), std::end(cont), Compare()) {}\n\n    template<class Container,\n             typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value, int>::type = 0>\n    explicit flat_map(const Container& cont, const Compare& comp)\n        : flat_map(std::begin(cont), std::end(cont), comp) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(const Container& cont, const Alloc& a)\n        : flat_map(std::begin(cont), std::end(cont), Compare(), a) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(const Container& cont, const Compare& comp, const Alloc& a)\n        : flat_map(std::begin(cont), std::end(cont), comp, a) {}\n\n    flat_map(sorted_unique_t, KeyContainer keys, MappedContainer values)\n        : c_{static_cast<KeyContainer&&>(keys), static_cast<MappedContainer&&>(values)}, compare_() {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(sorted_unique_t s, KeyContainer keys, MappedContainer values, const Alloc& a)\n        : flat_map(s, KeyContainer(static_cast<KeyContainer&&>(keys), a), MappedContainer(static_cast<MappedContainer&&>(values), a)) {}\n\n    template<class Container,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type>\n    flat_map(sorted_unique_t s, const Container& cont)\n        : flat_map(s, std::begin(cont), std::end(cont), Compare()) {}\n\n    template<class Container,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type>\n    flat_map(sorted_unique_t s, const Container& cont, const Compare& comp)\n        : flat_map(s, std::begin(cont), std::end(cont), comp) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(sorted_unique_t s, const Container& cont, const Alloc& a)\n        : flat_map(s, std::begin(cont), std::end(cont), Compare(), a) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(sorted_unique_t s, const Container& cont, const Compare& comp, const Alloc& a)\n        : flat_map(s, std::begin(cont), std::end(cont), comp, a) {}\n\n    explicit flat_map(const Compare& comp)\n        : c_{}, compare_(comp) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(const Compare& comp, const Alloc& a)\n        : c_{flatmap_detail::make_obj_using_allocator<KeyContainer>(a), flatmap_detail::make_obj_using_allocator<MappedContainer>(a)}, compare_(comp) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    explicit flat_map(const Alloc& a)\n        : flat_map(Compare(), a) {}\n\n    // TODO: shouldn't InputIterator be constrained to point to something with \"first\" and \"second\" members?\n    template<class InputIterator,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type>\n    flat_map(InputIterator first, InputIterator last, const Compare& comp = Compare())\n        : compare_(comp)\n    {\n        for (; first != last; ++first) {\n            c_.keys.insert(c_.keys.end(), first->first);\n            // TODO: we must make this exception-safe if the container insert throws\n            c_.values.insert(c_.values.end(), first->second);\n        }\n        this->sort_and_unique_impl();\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(InputIterator first, InputIterator last, const Compare& comp, const Alloc& a)\n        : c_{flatmap_detail::make_obj_using_allocator<KeyContainer>(a), flatmap_detail::make_obj_using_allocator<MappedContainer>(a)}, compare_(comp)\n    {\n        for (; first != last; ++first) {\n            c_.keys.insert(c_.keys.end(), first->first);\n            c_.values.insert(c_.values.end(), first->second);\n        }\n        this->sort_and_unique_impl();\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(InputIterator first, InputIterator last, const Alloc& a)\n        : flat_map(first, last, Compare(), a) {}\n\n    template<class InputIterator,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type>\n    flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Compare& comp = Compare())\n        : compare_(comp)\n    {\n        for (; first != last; ++first) {\n            c_.keys.insert(c_.keys.end(), first->first);\n            c_.values.insert(c_.values.end(), first->second);\n        }\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(sorted_unique_t, InputIterator first, InputIterator last, const Compare& comp, const Alloc& a)\n        : c_{flatmap_detail::make_obj_using_allocator<KeyContainer>(a), flatmap_detail::make_obj_using_allocator<MappedContainer>(a)}, compare_(comp)\n    {\n        for (; first != last; ++first) {\n            c_.keys.insert(c_.keys.end(), first->first);\n            c_.values.insert(c_.values.end(), first->second);\n        }\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<MappedContainer, Alloc>::value>::type>\n    flat_map(sorted_unique_t s, InputIterator first, InputIterator last, const Alloc& a)\n        : flat_map(s, first, last, Compare(), a) {}\n\n    // TODO: should this be conditionally noexcept?\n    // TODO: surely this should use uses-allocator construction\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(flat_map&& m, const Alloc& a)\n        : c_{KeyContainer(static_cast<KeyContainer&&>(m.c_.keys), a), MappedContainer(static_cast<MappedContainer&&>(m.c_.values), a)}, compare_(std::move(m.compare_)) {}\n\n    // TODO: surely this should use uses-allocator construction\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(const flat_map& m, const Alloc& a)\n        : c_{KeyContainer(m.c_.keys, a), MappedContainer(m.c_.values, a)}, compare_{m.compare_} {}\n\n    flat_map(std::initializer_list<value_type>&& il, const Compare& comp = Compare())\n        : flat_map(il, comp) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(std::initializer_list<value_type>&& il, const Compare& comp, const Alloc& a)\n        : flat_map(il, comp, a) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(std::initializer_list<value_type>&& il, const Alloc& a)\n        : flat_map(il, Compare(), a) {}\n\n    flat_map(sorted_unique_t s, std::initializer_list<value_type>&& il, const Compare& comp = Compare())\n        : flat_map(s, il, comp) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(sorted_unique_t s, std::initializer_list<value_type>&& il, const Compare& comp, const Alloc& a)\n        : flat_map(s, il, comp, a) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value && std::uses_allocator<MappedContainer, Alloc>::value, int>::type = 0>\n    flat_map(sorted_unique_t s, std::initializer_list<value_type>&& il, const Alloc& a)\n        : flat_map(s, il, Compare(), a) {}\n\n// ========================================================== OTHER MEMBERS\n\n    flat_map& operator=(std::initializer_list<value_type> il) {\n        this->clear();\n        this->insert(il);\n        return *this;\n    }\n\n    iterator begin() noexcept { return flatmap_detail::make_iterator(c_.keys.begin(), c_.values.begin()); }\n    const_iterator begin() const noexcept { return flatmap_detail::make_iterator(c_.keys.begin(), c_.values.begin()); }\n    iterator end() noexcept { return flatmap_detail::make_iterator(c_.keys.end(), c_.values.end()); }\n    const_iterator end() const noexcept { return flatmap_detail::make_iterator(c_.keys.end(), c_.values.end()); }\n\n    const_iterator cbegin() const noexcept { return flatmap_detail::make_iterator(c_.keys.begin(), c_.values.begin()); }\n    const_iterator cend() const noexcept { return flatmap_detail::make_iterator(c_.keys.end(), c_.values.end()); }\n\n    reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }\n    const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }\n    reverse_iterator rend() noexcept { return reverse_iterator(begin()); }\n    const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }\n\n    const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(begin()); }\n    const_reverse_iterator crend() const noexcept { return const_reverse_iterator(end()); }\n\n#if __cplusplus >= 201703L\n    [[nodiscard]]\n#endif\n    bool empty() const noexcept { return c_.keys.empty(); }\n    size_type size() const noexcept { return c_.keys.size(); }\n    size_type max_size() const noexcept { return std::min<size_type>(c_.keys.max_size(), c_.values.max_size()); }\n\n    mapped_reference operator[](const Key& x) {\n        return try_emplace(x).first->second;\n    }\n\n    mapped_reference operator[](Key&& x) {\n        return try_emplace(static_cast<Key&&>(x)).first->second;\n    }\n\n    mapped_reference at(const Key& k) {\n        auto it = this->find(k);\n        if (it == end()) {\n            throw std::out_of_range(\"flat_map::at\");\n        }\n        return it->second;\n    }\n\n    const_mapped_reference at(const Key& k) const {\n        auto it = this->find(k);\n        if (it == end()) {\n            throw std::out_of_range(\"flat_map::at\");\n        }\n        return it->second;\n    }\n\n    template<class... Args, class = decltype(std::pair<Key, Mapped>(std::declval<Args&&>()...), void())>\n    std::pair<iterator, bool> emplace(Args&&... args) {\n        std::pair<Key, Mapped> t(static_cast<Args&&>(args)...);\n        auto it = this->lower_bound(t.first);\n        if (it == end() || compare_(t.first, it->first)) {\n            auto kit = it.private_impl_getkey();\n            auto vit = it.private_impl_getmapped();\n            // TODO: we must make this exception-safe\n            kit = c_.keys.emplace(kit, static_cast<Key&&>(t.first));\n            vit = c_.values.emplace(vit, static_cast<Mapped&&>(t.second));\n            auto result = flatmap_detail::make_iterator(kit, vit);\n            return {std::move(result), true};\n        } else {\n            return {it, false};\n        }\n    }\n\n    template<class... Args>\n    iterator emplace_hint(const_iterator, Args&&... args) {\n        return this->emplace(static_cast<Args&&>(args)...).first;\n    }\n\n    std::pair<iterator, bool> insert(const value_type& x) {\n        return this->emplace(x);\n    }\n\n    std::pair<iterator, bool> insert(value_type&& x) {\n        return this->emplace(static_cast<value_type&&>(x));\n    }\n\n    iterator insert(const_iterator position, const value_type& x) {\n        return this->emplace_hint(position, x);\n    }\n\n    iterator insert(const_iterator position, value_type&& x) {\n        return this->emplace_hint(position, static_cast<value_type&&>(x));\n    }\n\n    template<class P,\n             class = decltype(std::pair<Key, Mapped>(std::declval<P&&>()))>\n    std::pair<iterator, bool> insert(P&& x) {\n        return this->emplace(static_cast<P&&>(x));\n    }\n\n    template<class P,\n             class = decltype(std::pair<Key, Mapped>(std::declval<P&&>()))>\n    iterator insert(const_iterator position, P&& x) {\n        return this->emplace_hint(position, static_cast<P&&>(x));\n    }\n\n    template<class InputIterator,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type>\n    void insert(InputIterator first, InputIterator last) {\n        // TODO: if we're inserting lots of elements, stick them at the end and then sort\n        while (first != last) {\n            this->insert(*first);\n            ++first;\n        }\n    }\n\n    template<class InputIterator,\n             class = typename std::enable_if<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value>::type>\n    void insert(stdext::sorted_unique_t, InputIterator first, InputIterator last) {\n        // TODO: if InputIterator is bidirectional, this loop should (go backward??)\n        // TODO: if we're inserting lots of elements, stick them at the end and then sort\n        auto it = begin();\n        while (first != last) {\n            std::pair<Key, Mapped> t(*first);\n            it = std::partition_point(it, this->end(), [&](const auto& elt) {\n                return bool(compare_(elt.first, t.first));\n            });\n            if (it == this->end() || bool(compare_(t.first, it->first))) {\n                it = this->emplace(it, std::move(t));\n            }\n            ++it;\n            ++first;\n        }\n    }\n\n    void insert(std::initializer_list<value_type> il) {\n        this->insert(il.begin(), il.end());\n    }\n\n    void insert(stdext::sorted_unique_t s, std::initializer_list<value_type> il) {\n        this->insert(s, il.begin(), il.end());\n    }\n\n    // TODO: as specified, this function fails to preserve the allocator, and has UB for std::pmr containers\n    containers extract() && {\n        try {\n            containers result{\n                static_cast<KeyContainer&&>(c_.keys),\n                static_cast<MappedContainer&&>(c_.values)\n            };\n            this->clear();\n            return result;\n        } catch (...) {\n            this->clear();\n            throw;\n        }\n    }\n\n    // TODO: why by rvalue reference and not by-value?\n    void replace(KeyContainer&& keys, MappedContainer&& values) {\n        try {\n            c_.keys = static_cast<KeyContainer&&>(keys);\n            c_.values = static_cast<MappedContainer&&>(values);\n        } catch (...) {\n            this->clear();\n            throw;\n        }\n    }\n\n    template<class... Args>\n    std::pair<iterator, bool> try_emplace(const Key& k, Args&&... args) {\n        auto kit = std::lower_bound(c_.keys.begin(), c_.keys.end(), k, std::ref(compare_));\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        if (kit == c_.keys.end() || compare_(k, *kit)) {\n            kit = c_.keys.insert(kit, k);\n            // TODO: we must make this exception-safe if the container throws\n            vit = c_.values.emplace(vit, static_cast<Args&&>(args)...);\n            return {flatmap_detail::make_iterator(kit, vit), true};\n        } else {\n            return {flatmap_detail::make_iterator(kit, vit), false};\n        }\n    }\n\n    template<class... Args>\n    std::pair<iterator, bool> try_emplace(Key&& k, Args&&... args) {\n        auto kit = std::lower_bound(c_.keys.begin(), c_.keys.end(), k, std::ref(compare_));\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        if (kit == c_.keys.end() || compare_(k, *kit)) {\n            kit = c_.keys.insert(kit, static_cast<Key&&>(k));\n            // TODO: we must make this exception-safe if the container throws\n            vit = c_.values.emplace(vit, static_cast<Args&&>(args)...);\n            return {flatmap_detail::make_iterator(kit, vit), true};\n        } else {\n            return {flatmap_detail::make_iterator(kit, vit), false};\n        }\n    }\n\n    // TODO: use the hint, here\n    template<class... Args>\n    iterator try_emplace(const_iterator, const Key& k, Args&&... args) {\n        return try_emplace(k, static_cast<Args&&>(args)...).first;\n    }\n\n    // TODO: use the hint, here\n    template<class... Args>\n    iterator try_emplace(const_iterator, Key&& k, Args&&... args) {\n        return try_emplace(static_cast<Key&&>(k), static_cast<Args&&>(args)...).first;\n    }\n\n    template<class M>\n    std::pair<iterator, bool> insert_or_assign(const Key& k, M&& obj) {\n        static_assert(std::is_assignable<Mapped&, M>::value, \"\");\n        static_assert(sizeof( Mapped(static_cast<M&&>(obj)) ) != 0, \"\");\n        auto result = try_emplace(k, static_cast<M&&>(obj));\n        if (!result.second) {\n            result.first->second = static_cast<M&&>(obj);\n        }\n        return result;\n    }\n\n    template<class M>\n    std::pair<iterator, bool> insert_or_assign(Key&& k, M&& obj) {\n        static_assert(std::is_assignable<Mapped&, M>::value, \"\");\n        static_assert(sizeof( Mapped(static_cast<M&&>(obj)) ) != 0, \"\");\n        auto result = try_emplace(static_cast<Key&&>(k), static_cast<M&&>(obj));\n        if (!result.second) {\n            result.first->second = static_cast<M&&>(obj);\n        }\n        return result;\n    }\n\n    // TODO: use the hint, here\n    template<class M>\n    iterator insert_or_assign(const_iterator, const Key& k, M&& obj) {\n        static_assert(std::is_assignable<Mapped&, M>::value, \"\");\n        static_assert(sizeof( Mapped(static_cast<M&&>(obj)) ) != 0, \"\");\n        auto result = try_emplace(k, static_cast<M&&>(obj));\n        if (!result.second) {\n            result.first->second = static_cast<M&&>(obj);\n        }\n        return result.first;\n    }\n\n    // TODO: use the hint, here\n    template<class M>\n    iterator insert_or_assign(const_iterator, Key&& k, M&& obj) {\n        static_assert(std::is_assignable<Mapped&, M>::value, \"\");\n        static_assert(sizeof( Mapped(static_cast<M&&>(obj)) ) != 0, \"\");\n        auto result = try_emplace(static_cast<Key&&>(k), static_cast<M&&>(obj));\n        if (!result.second) {\n            result.first->second = static_cast<M&&>(obj);\n        }\n        return result.first;\n    }\n\n    iterator erase(iterator position) {\n        auto kit = position.private_impl_getkey();\n        auto vit = position.private_impl_getmapped();\n        // TODO: what if either of these next two lines throws an exception?\n        auto kitmut = c_.keys.erase(kit);\n        auto vitmut = c_.values.erase(vit);\n        return flatmap_detail::make_iterator(kitmut, vitmut);\n    }\n\n    iterator erase(const_iterator position) {\n        auto kit = position.private_impl_getkey();\n        auto vit = position.private_impl_getmapped();\n        // TODO: what if either of these next two lines throws an exception?\n        auto kitmut = c_.keys.erase(kit);\n        auto vitmut = c_.values.erase(vit);\n        return flatmap_detail::make_iterator(kitmut, vitmut);\n    }\n\n    size_type erase(const Key& k) {\n        auto it = this->find(k);\n        if (it != this->end()) {\n            this->erase(it);\n            return 1;\n        }\n        return 0;\n    }\n\n    iterator erase(const_iterator first, const_iterator last) {\n        auto kfirst = first.private_impl_getkey();\n        auto vfirst = first.private_impl_getmapped();\n        auto klast = last.private_impl_getkey();\n        auto vlast = last.private_impl_getmapped();\n        // TODO: what if either of these next two lines throws an exception?\n        auto kitmut = c_.keys.erase(kfirst, klast);\n        auto vitmut = c_.values.erase(vfirst, vlast);\n        return flatmap_detail::make_iterator(kitmut, vitmut);\n    }\n\n    void swap(flat_map& fm) noexcept\n#if defined(__cpp_lib_is_swappable)\n        (std::is_nothrow_swappable<Compare>::value)\n#endif\n    {\n        using std::swap;\n        swap(compare_, fm.compare_);\n        swap(c_.keys, fm.c_.keys);\n        swap(c_.values, fm.c_.values);\n    }\n\n    void clear() noexcept {\n        c_.keys.clear();\n        c_.values.clear();\n    }\n\n    key_compare key_comp() const {\n        return compare_;\n    }\n\n    value_compare value_comp() const {\n        return value_compare(compare_);\n    }\n\n    const KeyContainer& keys() const {\n        return c_.keys;\n    }\n\n    const MappedContainer& values() const {\n        return c_.values;\n    }\n\n    iterator find(const Key& k) {\n        auto it = this->lower_bound(k);\n        if (it == end() || compare_(k, it->first)) {\n            return end();\n        }\n        return it;\n    }\n\n    const_iterator find(const Key& k) const {\n        auto it = this->lower_bound(k);\n        if (it == end() || compare_(k, it->first)) {\n            return end();\n        }\n        return it;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator find(const K& x) {\n        auto it = this->lower_bound(x);\n        if (it == end() || compare_(x, it->first)) {\n            return end();\n        }\n        return it;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator find(const K& x) const {\n        auto it = this->lower_bound(x);\n        if (it == end() || compare_(x, it->first)) {\n            return end();\n        }\n        return it;\n    }\n\n    size_type count(const Key& k) const {\n        return this->contains(k) ? 1 : 0;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    size_type count(const K& x) const {\n        return this->contains(x) ? 1 : 0;\n    }\n\n    bool contains(const Key& k) const {\n        return this->find(k) != this->end();\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    bool contains(const K& x) const {\n        return this->find(x) != this->end();\n    }\n\n    iterator lower_bound(const Key& k) {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, k));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    const_iterator lower_bound(const Key& k) const {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, k));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator lower_bound(const K& x) {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator lower_bound(const K& x) const {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    iterator upper_bound(const Key& k) {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(k, elt));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    const_iterator upper_bound(const Key& k) const {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(k, elt));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator upper_bound(const K& x) {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(x, elt));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator upper_bound(const K& x) const {\n        auto kit = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(x, elt));\n        });\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        return flatmap_detail::make_iterator(kit, vit);\n    }\n\n    std::pair<iterator, iterator> equal_range(const Key& k) {\n        auto kit1 = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, k));\n        });\n        auto kit2 = std::partition_point(kit1, c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(k, elt));\n        });\n        auto vit1 = c_.values.begin() + (kit1 - c_.keys.begin());\n        auto vit2 = c_.values.begin() + (kit2 - c_.keys.begin());\n        return {\n            flatmap_detail::make_iterator(kit1, vit1),\n            flatmap_detail::make_iterator(kit2, vit2)\n        };\n    }\n\n    std::pair<const_iterator, const_iterator> equal_range(const Key& k) const {\n        auto kit1 = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, k));\n        });\n        auto kit2 = std::partition_point(kit1, c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(k, elt));\n        });\n        auto vit1 = c_.values.begin() + (kit1 - c_.keys.begin());\n        auto vit2 = c_.values.begin() + (kit2 - c_.keys.begin());\n        return {\n            flatmap_detail::make_iterator(kit1, vit1),\n            flatmap_detail::make_iterator(kit2, vit2)\n        };\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    std::pair<iterator, iterator> equal_range(const K& x) {\n        auto kit1 = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto kit2 = std::partition_point(kit1, c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(x, elt));\n        });\n        auto vit1 = c_.values.begin() + (kit1 - c_.keys.begin());\n        auto vit2 = c_.values.begin() + (kit2 - c_.keys.begin());\n        return {\n            flatmap_detail::make_iterator(kit1, vit1),\n            flatmap_detail::make_iterator(kit2, vit2)\n        };\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    std::pair<const_iterator, const_iterator> equal_range(const K& x) const {\n        auto kit1 = std::partition_point(c_.keys.begin(), c_.keys.end(), [&](const auto& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto kit2 = std::partition_point(kit1, c_.keys.end(), [&](const auto& elt) {\n            return !bool(compare_(x, elt));\n        });\n        auto vit1 = c_.values.begin() + (kit1 - c_.keys.begin());\n        auto vit2 = c_.values.begin() + (kit2 - c_.keys.begin());\n        return {\n            flatmap_detail::make_iterator(kit1, vit1),\n            flatmap_detail::make_iterator(kit2, vit2)\n        };\n    }\n\nprivate:\n    void sort_and_unique_impl() {\n        flatmap_detail::sort_together(compare_, c_.keys, c_.values);\n        auto kit = flatmap_detail::unique_helper(c_.keys.begin(), c_.keys.end(), c_.values.begin(), compare_);\n        auto vit = c_.values.begin() + (kit - c_.keys.begin());\n        auto it = flatmap_detail::make_iterator(kit, vit);\n        this->erase(it, end());\n    }\n\n    containers c_;\n    Compare compare_;\n};\n\n// TODO: all six comparison operators should be invisible friends\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator==(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return std::equal(x.begin(), x.end(), y.begin(), y.end());\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator!=(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return !(x == y);\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator<(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator>(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return (y < x);\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator<=(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return !(y < x);\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nbool operator>=(const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, const flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y)\n{\n    return !(x < y);\n}\n\ntemplate<class Key, class Mapped, class Compare, class KeyContainer, class MappedContainer>\nvoid swap(flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& x, flat_map<Key, Mapped, Compare, KeyContainer, MappedContainer>& y) noexcept(noexcept(x.swap(y)))\n{\n    return x.swap(y);\n}\n\n#if defined(__cpp_deduction_guides)\n\n// TODO: this deduction guide should maybe be constrained by qualifies_as_range\ntemplate<class Container,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Container>::value>>\nflat_map(Container)\n    -> flat_map<flatmap_detail::cont_key_type<Container>, flatmap_detail::cont_mapped_type<Container>>;\n\ntemplate<class KeyContainer, class MappedContainer,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<KeyContainer>::value && !flatmap_detail::qualifies_as_allocator<MappedContainer>::value>>\nflat_map(KeyContainer, MappedContainer)\n    -> flat_map<typename KeyContainer::value_type,\n                typename MappedContainer::value_type,\n                std::less<typename KeyContainer::value_type>,\n                KeyContainer, MappedContainer>;\n\n// TODO: all these deduction guides that ignore the Allocator parameter are wrong, but especially this one\ntemplate<class Container, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Container>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value && std::uses_allocator<Container, Allocator>::value>>\nflat_map(Container, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<flatmap_detail::cont_key_type<Container>, flatmap_detail::cont_mapped_type<Container>>;\n\ntemplate<class KeyContainer, class MappedContainer, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<KeyContainer>::value && !flatmap_detail::qualifies_as_allocator<MappedContainer>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value && std::uses_allocator<KeyContainer, Allocator>::value && std::uses_allocator<MappedContainer, Allocator>::value>>\nflat_map(KeyContainer, MappedContainer, Allocator)\n    -> flat_map<typename KeyContainer::value_type,\n                typename MappedContainer::value_type,\n                std::less<typename KeyContainer::value_type>,\n                KeyContainer, MappedContainer>;\n\ntemplate<class Container,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Container>::value>>\nflat_map(sorted_unique_t, Container)\n    -> flat_map<flatmap_detail::cont_key_type<Container>, flatmap_detail::cont_mapped_type<Container>>;\n\ntemplate<class KeyContainer, class MappedContainer,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<KeyContainer>::value && !flatmap_detail::qualifies_as_allocator<MappedContainer>::value>>\nflat_map(sorted_unique_t, KeyContainer, MappedContainer)\n    -> flat_map<typename KeyContainer::value_type,\n                typename MappedContainer::value_type,\n                std::less<typename KeyContainer::value_type>,\n                KeyContainer, MappedContainer>;\n\ntemplate<class Container, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Container>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value && std::uses_allocator<Container, Allocator>::value>>\nflat_map(sorted_unique_t, Container, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<flatmap_detail::cont_key_type<Container>, flatmap_detail::cont_mapped_type<Container>>;\n\ntemplate<class KeyContainer, class MappedContainer, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<KeyContainer>::value && !flatmap_detail::qualifies_as_allocator<MappedContainer>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value && std::uses_allocator<KeyContainer, Allocator>::value && std::uses_allocator<MappedContainer, Allocator>::value>>\nflat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator)\n    -> flat_map<typename KeyContainer::value_type,\n                typename MappedContainer::value_type,\n                std::less<typename KeyContainer::value_type>,\n                KeyContainer, MappedContainer>;\n\ntemplate<class InputIterator, class Compare = std::less<flatmap_detail::iter_key_type<InputIterator>>,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && !flatmap_detail::qualifies_as_allocator<Compare>::value>>\nflat_map(InputIterator, InputIterator, Compare = Compare())\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Compare, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && !flatmap_detail::qualifies_as_allocator<Compare>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(InputIterator, InputIterator, Compare, Allocator)\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(InputIterator, InputIterator, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>>;\n\ntemplate<class InputIterator, class Compare = std::less<flatmap_detail::iter_key_type<InputIterator>>,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && !flatmap_detail::qualifies_as_allocator<Compare>::value>>\nflat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Compare, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && !flatmap_detail::qualifies_as_allocator<Compare>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(sorted_unique_t, InputIterator, InputIterator, Compare, Allocator)\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_input_iterator<InputIterator>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(sorted_unique_t, InputIterator, InputIterator, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<flatmap_detail::iter_key_type<InputIterator>, flatmap_detail::iter_mapped_type<InputIterator>>;\n\ntemplate<class Key, class T, class Compare = std::less<Key>,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Compare>::value>>\nflat_map(std::initializer_list<std::pair<const Key, T>>, Compare = Compare())\n    -> flat_map<Key, T, Compare>;\n\ntemplate<class Key, class T, class Compare, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Compare>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(std::initializer_list<std::pair<const Key, T>>, Compare, Allocator)\n    -> flat_map<Key, T, Compare>;\n\ntemplate<class Key, class T, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(std::initializer_list<std::pair<const Key, T>>, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<Key, T>;\n\ntemplate<class Key, class T, class Compare = std::less<Key>,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Compare>::value>>\nflat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Compare = Compare())\n    -> flat_map<Key, T, Compare>;\n\ntemplate<class Key, class T, class Compare, class Allocator,\n         class = std::enable_if_t<!flatmap_detail::qualifies_as_allocator<Compare>::value && flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Compare, Allocator)\n    -> flat_map<Key, T, Compare>;\n\ntemplate<class Key, class T, class Allocator,\n         class = std::enable_if_t<flatmap_detail::qualifies_as_allocator<Allocator>::value>>\nflat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Allocator, int=0/*to please MSVC*/)\n    -> flat_map<Key, T>;\n\n#endif\n\n} // namespace stdext\n"
  },
  {
    "path": "SG14/flat_set.h",
    "content": "/*\n * Boost Software License - Version 1.0 - August 17th, 2003\n *\n * Permission is hereby granted, free of charge, to any person or organization\n * obtaining a copy of the software and accompanying documentation covered by\n * this license (the \"Software\") to use, reproduce, display, distribute,\n * execute, and transmit the Software, and to prepare derivative works of the\n * Software, and to permit third-parties to whom the Software is furnished to\n * do so, all subject to the following:\n *\n * The copyright notices in the Software and this entire statement, including\n * the above license grant, this restriction and the following disclaimer,\n * must be included in all copies of the Software, in whole or in part, and\n * all derivative works of the Software, unless such copies or derivative\n * works are solely in the form of machine-executable object code generated by\n * a source language processor.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n */\n\n#pragma once\n\n// This is an implementation of the proposed \"std::flat_set\" as specified in\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1222r1.pdf\n\n#include <stddef.h>\n#include <algorithm>\n#include <functional>\n#include <initializer_list>\n#include <iterator>\n#include <vector>\n\nnamespace stdext {\n\nnamespace flatset_detail {\n    template<class T, class = void> struct qualifies_as_range : std::false_type {};\n    template<class T> struct qualifies_as_range<T, decltype(\n        std::begin( std::declval<T()>()() ), void(),\n        std::end( std::declval<T()>()() ), void()\n    )> : std::true_type {};\n\n    template<class It>\n    using is_random_access_iterator = std::is_convertible<\n        typename std::iterator_traits<It>::iterator_category,\n        std::random_access_iterator_tag\n    >;\n\n    template<int I> struct priority_tag : priority_tag<I-1> {};\n    template<> struct priority_tag<0> {};\n\n    // As proposed in P0591R4. Guaranteed copy elision makes this do the right thing.\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        std::uses_allocator<T, Alloc>::value && std::is_constructible<T, std::allocator_arg_t, const Alloc&, Args&&...>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<3>, const Alloc& alloc, Args&&... args) {\n        return T(std::allocator_arg, alloc, static_cast<Args&&>(args)...);\n    }\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        std::uses_allocator<T, Alloc>::value && std::is_constructible<T, Args&&..., const Alloc&>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<2>, const Alloc& alloc, Args&&... args) {\n        return T(static_cast<Args&&>(args)..., alloc);\n    }\n    template<class T, class Alloc, class... Args, class = typename std::enable_if<\n        !std::uses_allocator<T, Alloc>::value && std::is_constructible<T, Args&&...>::value\n    >::type>\n    T make_obj_using_allocator_(priority_tag<1>, const Alloc&, Args&&... args) {\n        return T(static_cast<Args&&>(args)...);\n    }\n    template<class T, class Alloc, class... Args>\n    T make_obj_using_allocator_(priority_tag<0>, const Alloc&, Args&&...) {\n        static_assert(sizeof(T)==0, \"this request for uses-allocator construction is ill-formed\");\n    }\n    template<class T, class Alloc, class... Args>\n    T make_obj_using_allocator(const Alloc& alloc, Args&&... args) {\n        return make_obj_using_allocator_<T>(priority_tag<3>(), alloc, static_cast<Args&&>(args)...);\n    }\n\n    template<class It, class Compare>\n    It unique_helper(It first, It last, Compare& compare) {\n        It dfirst = first;\n        while (first != last) {\n            It next = first;\n            ++next;\n            if ((next != last) && !bool(compare(*first, *next))) {\n                // \"next\" is a duplicate of \"first\", so do not preserve \"first\"\n            } else {\n                // do preserve \"first\"\n                if (first != dfirst) {\n                    *dfirst = std::move(*first);\n                }\n                ++dfirst;\n            }\n            first = next;\n        }\n        return dfirst;\n    }\n\n    template<class Container>\n    using cont_value_type = typename Container::value_type;\n\n    template<class InputIterator>\n    using iter_value_type = typename std::remove_const<typename std::iterator_traits<InputIterator>::value_type>::type;\n\n    template<class...> using void_t = void;\n\n    template<class A, class = void>\n    struct qualifies_as_allocator : std::false_type {};\n    template<class A>\n    struct qualifies_as_allocator<A, void_t<\n        typename A::value_type,\n        decltype(std::declval<A&>().allocate(size_t{}))\n    >> : std::true_type {};\n\n    template<class It>\n    using qualifies_as_input_iterator = std::integral_constant<bool, !std::is_integral<It>::value>;\n\n} // namespace flatset_detail\n\n#ifndef STDEXT_HAS_SORTED_UNIQUE\n#define STDEXT_HAS_SORTED_UNIQUE\n\nstruct sorted_unique_t { explicit sorted_unique_t() = default; };\n\n#if defined(__cpp_inline_variables)\ninline\n#endif\nconstexpr sorted_unique_t sorted_unique {};\n\n#endif // STDEXT_HAS_SORTED_UNIQUE\n\ntemplate<\n    class Key,\n    class Compare = std::less<Key>,\n    class KeyContainer = std::vector<Key>\n>\nclass flat_set {\n    static_assert(flatset_detail::is_random_access_iterator<typename KeyContainer::iterator>::value, \"\");\n    static_assert(std::is_same<Key, typename KeyContainer::value_type>::value, \"\");\n    static_assert(std::is_convertible<decltype(std::declval<const Compare&>()(std::declval<const Key&>(), std::declval<const Key&>())), bool>::value, \"\");\npublic:\n    using key_type = Key;\n    using key_compare = Compare;\n    using value_type = Key;\n    using value_compare = Compare;\n    using reference = Key&;\n    using const_reference = const Key&;\n    using size_type = size_t; // TODO: this should be KeyContainer::size_type\n    using difference_type = ptrdiff_t; // TODO: this should be KeyContainer::difference_type\n    using iterator = typename KeyContainer::iterator;\n    using const_iterator = typename KeyContainer::const_iterator;\n    using reverse_iterator = std::reverse_iterator<iterator>;\n    using const_reverse_iterator = std::reverse_iterator<const_iterator>;\n    using container_type = KeyContainer;\n\n// =========================================================== CONSTRUCTORS\n// This is all one massive overload set!\n\n    flat_set() : flat_set(Compare()) {}\n\n    explicit flat_set(KeyContainer ctr)\n        : c_(static_cast<KeyContainer&&>(ctr)), compare_()\n    {\n        this->sort_and_unique_impl();\n    }\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(KeyContainer&& ctr, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a, static_cast<KeyContainer&&>(ctr))), compare_()\n    {\n        this->sort_and_unique_impl();\n    }\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(const KeyContainer& ctr, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a, ctr)), compare_()\n    {\n        this->sort_and_unique_impl();\n    }\n\n    template<class Container,\n             typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value, int>::type = 0>\n    explicit flat_set(const Container& cont)\n        : flat_set(std::begin(cont), std::end(cont), Compare()) {}\n\n    template<class Container,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type>\n    flat_set(const Container& cont, const Compare& comp)\n        : flat_set(std::begin(cont), std::end(cont), comp) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(const Container& cont, const Alloc& a)\n        : flat_set(std::begin(cont), std::end(cont), Compare(), a) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(const Container& cont, const Compare& comp, const Alloc& a)\n        : flat_set(std::begin(cont), std::end(cont), comp, a) {}\n\n    flat_set(sorted_unique_t, KeyContainer ctr)\n        : c_(static_cast<KeyContainer&&>(ctr)), compare_() {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t, KeyContainer&& ctr, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a, static_cast<KeyContainer&&>(ctr))), compare_() {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t, const KeyContainer& ctr, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a, ctr)), compare_() {}\n\n    template<class Container,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type>\n    flat_set(sorted_unique_t s, const Container& cont)\n        : flat_set(s, std::begin(cont), std::end(cont), Compare()) {}\n\n    template<class Container,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type>\n    flat_set(sorted_unique_t s, const Container& cont, const Compare& comp)\n        : flat_set(s, std::begin(cont), std::end(cont), comp) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t s, const Container& cont, const Alloc& a)\n        : flat_set(s, std::begin(cont), std::end(cont), Compare(), a) {}\n\n    template<class Container, class Alloc,\n             class = typename std::enable_if<flatset_detail::qualifies_as_range<const Container&>::value>::type,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t s, const Container& cont, const Compare& comp, const Alloc& a)\n        : flat_set(s, std::begin(cont), std::end(cont), comp, a) {}\n\n    explicit flat_set(const Compare& comp)\n        : c_(), compare_(comp) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(const Compare& comp, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a)), compare_(comp) {}\n\n    template<class Alloc,\n             typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value, int>::type = 0>\n    explicit flat_set(const Alloc& a)\n        : flat_set(Compare(), a) {}\n\n    // TODO: all templates taking InputIterator probably need to be constrained\n    template<class InputIterator>\n    flat_set(InputIterator first, InputIterator last, const Compare& comp = Compare())\n        : c_(first, last), compare_(comp)\n    {\n        this->sort_and_unique_impl();\n    }\n\n    // TODO: this constructor should conditionally use KeyContainer's iterator-pair constructor\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(InputIterator first, InputIterator last, const Compare& comp, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a)), compare_(comp)\n    {\n        while (first != last) {\n            c_.insert(c_.end(), *first);\n            ++first;\n        }\n        this->sort_and_unique_impl();\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(InputIterator first, InputIterator last, const Alloc& a)\n        : flat_set(first, last, Compare(), a) {}\n\n    template<class InputIterator>\n    flat_set(sorted_unique_t, InputIterator first, InputIterator last, const Compare& comp = Compare())\n        : c_(first, last), compare_(comp) {}\n\n    // TODO: this constructor should conditionally use KeyContainer's iterator-pair constructor\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t, InputIterator first, InputIterator last,\n             const Compare& comp, const Alloc& a)\n        : c_(flatset_detail::make_obj_using_allocator<KeyContainer>(a)), compare_(comp)\n    {\n        while (first != last) {\n            c_.insert(c_.end(), *first);\n            ++first;\n        }\n    }\n\n    template<class InputIterator, class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t s, InputIterator first, InputIterator last, const Alloc& a)\n        : flat_set(s, first, last, Compare(), a) {}\n\n    // TODO: should this be conditionally noexcept?\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(flat_set&& m, const Alloc& a)\n        : c_(static_cast<KeyContainer&&>(m.c_), a), compare_(static_cast<Compare&&>(m.compare_)) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(const flat_set& m, const Alloc& a)\n        : c_(m.c_, a), compare_(m.compare_) {}\n\n    flat_set(std::initializer_list<Key>&& il, const Compare& comp = Compare())\n        : flat_set(il, comp) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(std::initializer_list<Key>&& il, const Compare& comp, const Alloc& a)\n        : flat_set(il, comp, a) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(std::initializer_list<Key>&& il, const Alloc& a)\n        : flat_set(il, Compare(), a) {}\n\n    flat_set(sorted_unique_t s, std::initializer_list<Key>&& il, const Compare& comp = Compare())\n        : flat_set(s, il, comp) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t s, std::initializer_list<Key>&& il, const Compare& comp, const Alloc& a)\n        : flat_set(s, il, comp, a) {}\n\n    template<class Alloc,\n             class = typename std::enable_if<std::uses_allocator<KeyContainer, Alloc>::value>::type>\n    flat_set(sorted_unique_t s, std::initializer_list<Key>&& il, const Alloc& a)\n        : flat_set(s, il, Compare(), a) {}\n\n\n// ========================================================== OTHER MEMBERS\n\n    flat_set& operator=(std::initializer_list<Key> il) {\n        this->clear();\n        this->insert(il);\n        return *this;\n    }\n\n    iterator begin() noexcept { return c_.begin(); }\n    const_iterator begin() const noexcept { return c_.begin(); }\n    iterator end() noexcept { return c_.end(); }\n    const_iterator end() const noexcept { return c_.end(); }\n\n    const_iterator cbegin() const noexcept { return c_.begin(); }\n    const_iterator cend() const noexcept { return c_.end(); }\n\n    reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }\n    const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }\n    reverse_iterator rend() noexcept { return reverse_iterator(begin()); }\n    const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }\n\n    const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }\n    const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }\n\n#if __cplusplus >= 201703L\n    [[nodiscard]]\n#endif\n    bool empty() const noexcept { return c_.empty(); }\n    size_type size() const noexcept { return c_.size(); }\n    size_type max_size() const noexcept { return c_.max_size(); }\n\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&&... args) {\n        Key t(static_cast<Args&&>(args)...);\n        auto it = this->lower_bound(t);\n        if (it == end() || compare_(t, *it)) {\n            it = c_.emplace(it, static_cast<Key&&>(t));\n            return {it, true};\n        } else {\n            return {it, false};\n        }\n    }\n\n    // TODO: this function cannot possibly meet its amortized-constant-complexity requirement\n    template<class... Args>\n    iterator emplace_hint(const_iterator, Args&&... args) {\n        return this->emplace(static_cast<Args&&>(args)...).first;\n    }\n\n    std::pair<iterator, bool> insert(const Key& t) {\n        auto it = this->lower_bound(t);\n        if (it == c_.end() || compare_(t, *it)) {\n            it = c_.emplace(it, t);\n            return {it, true};\n        } else {\n            return {it, false};\n        }\n    }\n\n    std::pair<iterator, bool> insert(Key&& t) {\n        auto it = this->lower_bound(t);\n        if (it == c_.end() || compare_(t, *it)) {\n            it = c_.emplace(it, static_cast<Key&&>(t));\n            return {it, true};\n        } else {\n            return {it, false};\n        }\n    }\n\n    // TODO: this function cannot possibly meet its amortized-constant-complexity requirement\n    iterator insert(const_iterator, const Key& t) {\n        return this->insert(t).first;\n    }\n\n    // TODO: this function cannot possibly meet its amortized-constant-complexity requirement\n    iterator insert(const_iterator, Key&& t) {\n        return this->insert(static_cast<Key&&>(t)).first;\n    }\n\n    template<class InputIterator>\n    void insert(InputIterator first, InputIterator last) {\n        while (first != last) {\n            this->insert(*first);\n            ++first;\n        }\n    }\n\n    template<class InputIterator>\n    void insert(sorted_unique_t, InputIterator first, InputIterator last) {\n        auto it = begin();\n        while (first != last) {\n            Key t(*first);\n            it = std::partition_point(it, end(), [&](const Key& elt) {\n                return bool(compare_(elt, t));\n            });\n            if (it == end() || compare_(t, *it)) {\n                it = c_.emplace(it, static_cast<Key&&>(t));\n            }\n            ++it;\n            ++first;\n        }\n    }\n\n    void insert(std::initializer_list<Key> il) {\n        this->insert(il.begin(), il.end());\n    }\n\n    void insert(sorted_unique_t s, std::initializer_list<Key> il) {\n        this->insert(s, il.begin(), il.end());\n    }\n\n    KeyContainer extract() && {\n        KeyContainer result = static_cast<KeyContainer&&>(c_);\n        clear();\n        return result;\n    }\n\n    void replace(KeyContainer&& ctr) {\n        c_ = static_cast<KeyContainer&&>(ctr);\n    }\n\n    iterator erase(iterator position) {\n        return c_.erase(position);\n    }\n\n    iterator erase(const_iterator position) {\n        return c_.erase(position);\n    }\n\n    size_type erase(const Key& t) {\n        auto it = this->find(t);\n        if (it != this->end()) {\n            this->erase(it);\n            return 1;\n        }\n        return 0;\n    }\n\n    iterator erase(const_iterator first, const_iterator last) {\n        c_.erase(first, last);\n    }\n\n    void swap(flat_set& m) noexcept\n#if defined(__cpp_lib_is_swappable)\n        (std::is_nothrow_swappable<KeyContainer>::value && std::is_nothrow_swappable<Compare>::value)\n#endif\n    {\n        using std::swap;\n        swap(compare_, m.compare_);\n        swap(c_, m.c_);\n    }\n\n    void clear() noexcept {\n        c_.clear();\n    }\n\n    Compare key_comp() const { return compare_; }\n    Compare value_comp() const { return compare_; }\n\n    iterator find(const Key& t) {\n        auto it = this->lower_bound(t);\n        if (it == this->end() || compare_(t, *it)) {\n            return this->end();\n        }\n        return it;\n    }\n\n    const_iterator find(const Key& t) const {\n        auto it = this->lower_bound(t);\n        if (it == this->end() || compare_(t, *it)) {\n            return this->end();\n        }\n        return it;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator find(const K& x) {\n        auto it = this->lower_bound(x);\n        if (it == this->end() || compare_(x, *it)) {\n            return this->end();\n        }\n        return it;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator find(const K& x) const {\n        auto it = this->lower_bound(x);\n        if (it == this->end() || compare_(x, *it)) {\n            return this->end();\n        }\n        return it;\n    }\n\n    size_type count(const Key& x) const {\n        return this->contains(x) ? 1 : 0;\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    size_type count(const K& x) const {\n        return this->contains(x) ? 1 : 0;\n    }\n\n    bool contains(const Key& x) const {\n        return this->find(x) != this->end();\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    bool contains(const K& x) const {\n        return this->find(x) != this->end();\n    }\n\n    iterator lower_bound(const Key& t) {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, t));\n        });\n    }\n\n    const_iterator lower_bound(const Key& t) const {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, t));\n        });\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator lower_bound(const K& x) {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, x));\n        });\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator lower_bound(const K& x) const {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, x));\n        });\n    }\n\n    iterator upper_bound(const Key& t) {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return !bool(compare_(t, elt));\n        });\n    }\n\n    const_iterator upper_bound(const Key& t) const {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return !bool(compare_(t, elt));\n        });\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    iterator upper_bound(const K& x) {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return !bool(compare_(x, elt));\n        });\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    const_iterator upper_bound(const K& x) const {\n        return std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return !bool(compare_(x, elt));\n        });\n    }\n\n    std::pair<iterator, iterator> equal_range(const Key& t) {\n        auto lo = std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, t));\n        });\n        auto hi = std::partition_point(lo, this->end(), [&](const Key& elt) {\n            return !bool(compare_(t, elt));\n        });\n        return { lo, hi };\n    }\n\n    std::pair<const_iterator, const_iterator> equal_range(const Key& t) const {\n        auto lo = std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, t));\n        });\n        auto hi = std::partition_point(lo, this->end(), [&](const Key& elt) {\n            return !bool(compare_(t, elt));\n        });\n        return { lo, hi };\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    std::pair<iterator, iterator> equal_range(const K& x) {\n        auto lo = std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto hi = std::partition_point(lo, this->end(), [&](const Key& elt) {\n            return !bool(compare_(x, elt));\n        });\n        return { lo, hi };\n    }\n\n    template<class K,\n             class Compare_ = Compare, class = typename Compare_::is_transparent>\n    std::pair<const_iterator, const_iterator> equal_range(const K& x) const {\n        auto lo = std::partition_point(this->begin(), this->end(), [&](const Key& elt) {\n            return bool(compare_(elt, x));\n        });\n        auto hi = std::partition_point(lo, this->end(), [&](const Key& elt) {\n            return !bool(compare_(x, elt));\n        });\n        return { lo, hi };\n    }\n\nprivate:\n    void sort_and_unique_impl() {\n        std::sort(c_.begin(), c_.end(), compare_);\n        auto it = flatset_detail::unique_helper(c_.begin(), c_.end(), compare_);\n        c_.erase(it, c_.end());\n    }\n\n    KeyContainer c_;\n    Compare compare_;\n};\n\n// TODO: all six comparison operators should be invisible friends\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator==(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return std::equal(x.begin(), x.end(), y.begin(), y.end());\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator!=(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return !(x == y);\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator<(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator>(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return (y < x);\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator<=(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return !(y < x);\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nbool operator>=(const flat_set<Key, Compare, KeyContainer>& x, const flat_set<Key, Compare, KeyContainer>& y)\n{\n    return !(x < y);\n}\n\ntemplate<class Key, class Compare, class KeyContainer>\nvoid swap(flat_set<Key, Compare, KeyContainer>& x, flat_set<Key, Compare, KeyContainer>& y) noexcept(noexcept(x.swap(y)))\n{\n    return x.swap(y);\n}\n\n#if defined(__cpp_deduction_guides)\n\n// TODO: this deduction guide should maybe be constrained by qualifies_as_range\ntemplate<class Container,\n         class = std::enable_if_t<!flatset_detail::qualifies_as_allocator<Container>::value>>\nflat_set(Container)\n    -> flat_set<flatset_detail::cont_value_type<Container>>;\n\ntemplate<class Container, class Allocator,\n         class = std::enable_if_t<!flatset_detail::qualifies_as_allocator<Container>::value &&\n                                  flatset_detail::qualifies_as_allocator<Allocator>::value &&\n                                  std::uses_allocator<Container, Allocator>::value>>\nflat_set(Container, Allocator)\n    -> flat_set<flatset_detail::cont_value_type<Container>>;\n\ntemplate<class Container,\n         class = std::enable_if_t<!flatset_detail::qualifies_as_allocator<Container>::value>>\nflat_set(sorted_unique_t, Container)\n    -> flat_set<flatset_detail::cont_value_type<Container>>;\n\ntemplate<class Container, class Allocator,\n         class = std::enable_if_t<!flatset_detail::qualifies_as_allocator<Container>::value &&\n                                  flatset_detail::qualifies_as_allocator<Allocator>::value &&\n                                  std::uses_allocator<Container, Allocator>::value>>\nflat_set(sorted_unique_t, Container, Allocator)\n    -> flat_set<flatset_detail::cont_value_type<Container>>;\n\ntemplate<class InputIterator, class Compare = std::less<flatset_detail::iter_value_type<InputIterator>>,\n         class = std::enable_if_t<flatset_detail::qualifies_as_input_iterator<InputIterator>::value &&\n                                  !flatset_detail::qualifies_as_allocator<Compare>::value>>\nflat_set(InputIterator, InputIterator, Compare = Compare())\n    -> flat_set<flatset_detail::iter_value_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Compare, class Allocator,\n         class = std::enable_if_t<flatset_detail::qualifies_as_input_iterator<InputIterator>::value &&\n                                  !flatset_detail::qualifies_as_allocator<Compare>::value &&\n                                  flatset_detail::qualifies_as_allocator<Allocator>::value>>\nflat_set(InputIterator, InputIterator, Compare, Allocator)\n    -> flat_set<flatset_detail::iter_value_type<InputIterator>, Compare>;\n\ntemplate<class InputIterator, class Allocator,\n         class = std::enable_if_t<flatset_detail::qualifies_as_input_iterator<InputIterator>::value &&\n                                  flatset_detail::qualifies_as_allocator<Allocator>::value>>\nflat_set(InputIterator, InputIterator, Allocator, int=0/*to please MSVC*/)\n    -> flat_set<flatset_detail::iter_value_type<InputIterator>>;\n\n#endif\n\n} // namespace stdext\n"
  },
  {
    "path": "SG14/inplace_function.h",
    "content": "/*\n * Boost Software License - Version 1.0 - August 17th, 2003\n *\n * Permission is hereby granted, free of charge, to any person or organization\n * obtaining a copy of the software and accompanying documentation covered by\n * this license (the \"Software\") to use, reproduce, display, distribute,\n * execute, and transmit the Software, and to prepare derivative works of the\n * Software, and to permit third-parties to whom the Software is furnished to\n * do so, all subject to the following:\n *\n * The copyright notices in the Software and this entire statement, including\n * the above license grant, this restriction and the following disclaimer,\n * must be included in all copies of the Software, in whole or in part, and\n * all derivative works of the Software, unless such copies or derivative\n * works are solely in the form of machine-executable object code generated by\n * a source language processor.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n */\n\n#pragma once\n\n#include <type_traits>\n#include <utility>\n#include <functional>\n\n#ifndef SG14_INPLACE_FUNCTION_THROW\n#define SG14_INPLACE_FUNCTION_THROW(x) throw (x)\n#endif\n\nnamespace stdext {\n\nnamespace inplace_function_detail {\n\nstatic constexpr size_t InplaceFunctionDefaultCapacity = 32;\n\n#ifndef SG14_USE_STD_ALIGNED_STORAGE\n// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61458\n// MSVC 32-bit has the same bug.\n// libc++ and MSVC 64-bit seem to work fine right now, but why run the risk?\ntemplate<size_t Cap>\nunion aligned_storage_helper {\n    struct double1 { double a; };\n    struct double4 { double a[4]; };\n    template<class T> using maybe = std::conditional_t<(Cap >= sizeof(T)), T, char>;\n    char real_data[Cap];\n    maybe<int> a;\n    maybe<long> b;\n    maybe<long long> c;\n    maybe<void*> d;\n    maybe<void(*)()> e;\n    maybe<double1> f;\n    maybe<double4> g;\n    maybe<long double> h;\n};\n\ntemplate<size_t Cap, size_t Align = alignof(aligned_storage_helper<Cap>)>\nstruct aligned_storage {\n    using type = std::aligned_storage_t<Cap, Align>;\n};\n\ntemplate<size_t Cap, size_t Align = alignof(aligned_storage_helper<Cap>)>\nusing aligned_storage_t = typename aligned_storage<Cap, Align>::type;\nstatic_assert(sizeof(aligned_storage_t<sizeof(void*)>) == sizeof(void*), \"A\");\nstatic_assert(alignof(aligned_storage_t<sizeof(void*)>) == alignof(void*), \"B\");\n#else\nusing std::aligned_storage;\nusing std::aligned_storage_t;\nstatic_assert(sizeof(std::aligned_storage_t<sizeof(void*)>) == sizeof(void*), \"C\");\nstatic_assert(alignof(std::aligned_storage_t<sizeof(void*)>) == alignof(void*), \"D\");\n#endif\n\ntemplate<class T> struct wrapper\n{\n    using type = T;\n};\n\ntemplate<class R, class... Args> struct vtable\n{\n    using storage_ptr_t = void*;\n\n    using invoke_ptr_t = R(*)(storage_ptr_t, Args&&...);\n    using process_ptr_t = void(*)(storage_ptr_t, storage_ptr_t);\n    using destructor_ptr_t = void(*)(storage_ptr_t);\n\n    const invoke_ptr_t invoke_ptr;\n    const process_ptr_t copy_ptr;\n    const process_ptr_t relocate_ptr;\n    const destructor_ptr_t destructor_ptr;\n\n    explicit constexpr vtable() noexcept :\n        invoke_ptr{ [](storage_ptr_t, Args&&...) -> R\n            { SG14_INPLACE_FUNCTION_THROW(std::bad_function_call()); }\n        },\n        copy_ptr{ [](storage_ptr_t, storage_ptr_t) -> void {} },\n        relocate_ptr{ [](storage_ptr_t, storage_ptr_t) -> void {} },\n        destructor_ptr{ [](storage_ptr_t) -> void {} }\n    {}\n\n    template<class C> explicit constexpr vtable(wrapper<C>) noexcept :\n        invoke_ptr{ [](storage_ptr_t storage_ptr, Args&&... args) -> R\n            { return (*static_cast<C*>(storage_ptr))(\n                static_cast<Args&&>(args)...\n            ); }\n        },\n        copy_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr) -> void\n            { ::new (dst_ptr) C{ (*static_cast<C*>(src_ptr)) }; }\n        },\n        relocate_ptr{ [](storage_ptr_t dst_ptr, storage_ptr_t src_ptr) -> void\n            {\n                ::new (dst_ptr) C{ std::move(*static_cast<C*>(src_ptr)) };\n                static_cast<C*>(src_ptr)->~C();\n            }\n        },\n        destructor_ptr{ [](storage_ptr_t src_ptr) -> void\n            { static_cast<C*>(src_ptr)->~C(); }\n        }\n    {}\n\n    vtable(const vtable&) = delete;\n    vtable(vtable&&) = delete;\n\n    vtable& operator= (const vtable&) = delete;\n    vtable& operator= (vtable&&) = delete;\n\n    ~vtable() = default;\n};\n\ntemplate<class R, class... Args>\n#if __cplusplus >= 201703L\ninline constexpr\n#endif\nvtable<R, Args...> empty_vtable{};\n\ntemplate<size_t DstCap, size_t DstAlign, size_t SrcCap, size_t SrcAlign>\nstruct is_valid_inplace_dst : std::true_type\n{\n    static_assert(DstCap >= SrcCap,\n        \"Can't squeeze larger inplace_function into a smaller one\"\n    );\n\n    static_assert(DstAlign % SrcAlign == 0,\n        \"Incompatible inplace_function alignments\"\n    );\n};\n\n// C++11 MSVC compatible implementation of std::is_invocable_r.\n\ntemplate<class R> void accept(R);\n\ntemplate<class, class R, class F, class... Args> struct is_invocable_r_impl : std::false_type {};\n\ntemplate<class F, class... Args> struct is_invocable_r_impl<\n    decltype(std::declval<F>()(std::declval<Args>()...), void()),\n    void,\n    F,\n    Args...\n> : std::true_type {};\n\ntemplate<class F, class... Args> struct is_invocable_r_impl<\n    decltype(std::declval<F>()(std::declval<Args>()...), void()),\n    const void,\n    F,\n    Args...\n> : std::true_type {};\n\ntemplate<class R, class F, class... Args> struct is_invocable_r_impl<\n    decltype(accept<R>(std::declval<F>()(std::declval<Args>()...))),\n    R,\n    F,\n    Args...\n> : std::true_type {};\n\ntemplate<class R, class F, class... Args> using is_invocable_r = is_invocable_r_impl<\n    void,\n    R,\n    F,\n    Args...\n>;\n} // namespace inplace_function_detail\n\ntemplate<\n    class Signature,\n    size_t Capacity = inplace_function_detail::InplaceFunctionDefaultCapacity,\n    size_t Alignment = alignof(inplace_function_detail::aligned_storage_t<Capacity>)\n>\nclass inplace_function; // unspecified\n\nnamespace inplace_function_detail {\n    template<class> struct is_inplace_function : std::false_type {};\n    template<class Sig, size_t Cap, size_t Align>\n    struct is_inplace_function<inplace_function<Sig, Cap, Align>> : std::true_type {};\n} // namespace inplace_function_detail\n\ntemplate<\n    class R,\n    class... Args,\n    size_t Capacity,\n    size_t Alignment\n>\nclass inplace_function<R(Args...), Capacity, Alignment>\n{\n    using storage_t = inplace_function_detail::aligned_storage_t<Capacity, Alignment>;\n    using vtable_t = inplace_function_detail::vtable<R, Args...>;\n    using vtable_ptr_t = const vtable_t*;\n\n    template <class, size_t, size_t> friend class inplace_function;\n\npublic:\n    using capacity = std::integral_constant<size_t, Capacity>;\n    using alignment = std::integral_constant<size_t, Alignment>;\n\n    inplace_function() noexcept :\n        vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable<R, Args...>)}\n    {}\n\n    template<\n        class T,\n        class C = std::decay_t<T>,\n        class = std::enable_if_t<\n            !inplace_function_detail::is_inplace_function<C>::value\n            && inplace_function_detail::is_invocable_r<R, C&, Args...>::value\n        >\n    >\n    inplace_function(T&& closure)\n    {\n        static_assert(std::is_copy_constructible<C>::value,\n            \"inplace_function cannot be constructed from non-copyable type\"\n        );\n\n        static_assert(sizeof(C) <= Capacity,\n            \"inplace_function cannot be constructed from object with this (large) size\"\n        );\n\n        static_assert(Alignment % alignof(C) == 0,\n            \"inplace_function cannot be constructed from object with this (large) alignment\"\n        );\n\n        static const vtable_t vt{inplace_function_detail::wrapper<C>{}};\n        vtable_ptr_ = std::addressof(vt);\n\n        ::new (std::addressof(storage_)) C{std::forward<T>(closure)};\n    }\n\n    template<size_t Cap, size_t Align>\n    inplace_function(const inplace_function<R(Args...), Cap, Align>& other)\n        : inplace_function(other.vtable_ptr_, other.vtable_ptr_->copy_ptr, std::addressof(other.storage_))\n    {\n        static_assert(inplace_function_detail::is_valid_inplace_dst<\n            Capacity, Alignment, Cap, Align\n        >::value, \"conversion not allowed\");\n    }\n\n    template<size_t Cap, size_t Align>\n    inplace_function(inplace_function<R(Args...), Cap, Align>&& other) noexcept\n        : inplace_function(other.vtable_ptr_, other.vtable_ptr_->relocate_ptr, std::addressof(other.storage_))\n    {\n        static_assert(inplace_function_detail::is_valid_inplace_dst<\n            Capacity, Alignment, Cap, Align\n        >::value, \"conversion not allowed\");\n\n        other.vtable_ptr_ = std::addressof(inplace_function_detail::empty_vtable<R, Args...>);\n    }\n\n    inplace_function(std::nullptr_t) noexcept :\n        vtable_ptr_{std::addressof(inplace_function_detail::empty_vtable<R, Args...>)}\n    {}\n\n    inplace_function(const inplace_function& other) :\n        vtable_ptr_{other.vtable_ptr_}\n    {\n        vtable_ptr_->copy_ptr(\n            std::addressof(storage_),\n            std::addressof(other.storage_)\n        );\n    }\n\n    inplace_function(inplace_function&& other) noexcept :\n        vtable_ptr_{std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable<R, Args...>))}\n    {\n        vtable_ptr_->relocate_ptr(\n            std::addressof(storage_),\n            std::addressof(other.storage_)\n        );\n    }\n\n    inplace_function& operator= (std::nullptr_t) noexcept\n    {\n        vtable_ptr_->destructor_ptr(std::addressof(storage_));\n        vtable_ptr_ = std::addressof(inplace_function_detail::empty_vtable<R, Args...>);\n        return *this;\n    }\n\n    inplace_function& operator= (inplace_function other) noexcept\n    {\n        vtable_ptr_->destructor_ptr(std::addressof(storage_));\n\n        vtable_ptr_ = std::exchange(other.vtable_ptr_, std::addressof(inplace_function_detail::empty_vtable<R, Args...>));\n        vtable_ptr_->relocate_ptr(\n            std::addressof(storage_),\n            std::addressof(other.storage_)\n        );\n        return *this;\n    }\n\n    ~inplace_function()\n    {\n        vtable_ptr_->destructor_ptr(std::addressof(storage_));\n    }\n\n    R operator() (Args... args) const\n    {\n        return vtable_ptr_->invoke_ptr(\n            std::addressof(storage_),\n            std::forward<Args>(args)...\n        );\n    }\n\n    constexpr bool operator== (std::nullptr_t) const noexcept\n    {\n        return !operator bool();\n    }\n\n    constexpr bool operator!= (std::nullptr_t) const noexcept\n    {\n        return operator bool();\n    }\n\n    explicit constexpr operator bool() const noexcept\n    {\n        return vtable_ptr_ != std::addressof(inplace_function_detail::empty_vtable<R, Args...>);\n    }\n\n    void swap(inplace_function& other) noexcept\n    {\n        if (this == std::addressof(other)) return;\n\n        storage_t tmp;\n        vtable_ptr_->relocate_ptr(\n            std::addressof(tmp),\n            std::addressof(storage_)\n        );\n\n        other.vtable_ptr_->relocate_ptr(\n            std::addressof(storage_),\n            std::addressof(other.storage_)\n        );\n\n        vtable_ptr_->relocate_ptr(\n            std::addressof(other.storage_),\n            std::addressof(tmp)\n        );\n\n        std::swap(vtable_ptr_, other.vtable_ptr_);\n    }\n\n    friend void swap(inplace_function& lhs, inplace_function& rhs) noexcept\n    {\n        lhs.swap(rhs);\n    }\n\nprivate:\n    vtable_ptr_t vtable_ptr_;\n    mutable storage_t storage_;\n\n    inplace_function(\n        vtable_ptr_t vtable_ptr,\n        typename vtable_t::process_ptr_t process_ptr,\n        typename vtable_t::storage_ptr_t storage_ptr\n    ) : vtable_ptr_{vtable_ptr}\n    {\n        process_ptr(std::addressof(storage_), storage_ptr);\n    }\n};\n\n} // namespace stdext\n"
  },
  {
    "path": "SG14/plf_colony.h",
    "content": "// Copyright (c) 2021, Matthew Bentley (mattreecebentley@gmail.com) www.plflib.org\r\n\r\n// zLib license (https://www.zlib.net/zlib_license.html):\r\n// This software is provided 'as-is', without any express or implied\r\n// warranty. In no event will the authors be held liable for any damages\r\n// arising from the use of this software.\r\n//\r\n// Permission is granted to anyone to use this software for any purpose,\r\n// including commercial applications, and to alter it and redistribute it\r\n// freely, subject to the following restrictions:\r\n//\r\n// 1. The origin of this software must not be misrepresented; you must not\r\n// \tclaim that you wrote the original software. If you use this software\r\n// \tin a product, an acknowledgement in the product documentation would be\r\n// \tappreciated but is not required.\r\n// 2. Altered source versions must be plainly marked as such, and must not be\r\n// \tmisrepresented as being the original software.\r\n// 3. This notice may not be removed or altered from any source distribution.\r\n\r\n\r\n#ifndef PLF_COLONY_H\r\n#define PLF_COLONY_H\r\n\r\n\r\n// Compiler-specific defines:\r\n\r\n#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)\r\n\t#define PLF_FORCE_INLINE __forceinline\r\n\r\n\t#if _MSC_VER >= 1600\r\n\t\t#define PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t#define PLF_STATIC_ASSERT(check, message) static_assert(check, message)\r\n\t#else\r\n\t\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t#endif\r\n\t#if _MSC_VER >= 1700\r\n\t\t#define PLF_TYPE_TRAITS_SUPPORT\r\n\t\t#define PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t#endif\r\n\t#if _MSC_VER >= 1800\r\n\t\t#define PLF_VARIADICS_SUPPORT // Variadics, in this context, means both variadic templates and variadic macros are supported\r\n\t\t#define PLF_INITIALIZER_LIST_SUPPORT\r\n\t#endif\r\n\t#if _MSC_VER >= 1900\r\n\t\t#define PLF_ALIGNMENT_SUPPORT\r\n\t\t#define PLF_NOEXCEPT noexcept\r\n\t\t#define PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\t#else\r\n\t\t#define PLF_NOEXCEPT throw()\r\n\t#endif\r\n\r\n\t#if defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)\r\n\t\t#define PLF_CONSTEXPR constexpr\r\n\t#else\r\n\t\t#define PLF_CONSTEXPR\r\n\t#endif\r\n\r\n\t#if defined(_MSVC_LANG) && (_MSVC_LANG > 201703L) && _MSC_VER >= 1923\r\n\t\t#define PLF_CPP20_SUPPORT\r\n\t#endif\r\n#elif defined(__cplusplus) && __cplusplus >= 201103L // C++11 support, at least\r\n\t#define PLF_FORCE_INLINE // note: GCC and clang create faster code without forcing inline\r\n\r\n\t#if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 // 4.2 and below do not support variadic templates\r\n\t\t\t#define PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#define PLF_VARIADICS_SUPPORT\r\n\t\t\t#define PLF_STATIC_ASSERT(check, message) static_assert(check, message)\r\n\t\t#else\r\n\t\t\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t\t#endif\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 // 4.3 and below do not support initializer lists\r\n\t\t\t#define PLF_INITIALIZER_LIST_SUPPORT\r\n\t\t#endif\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4\r\n\t\t\t#define PLF_NOEXCEPT noexcept\r\n\t\t#else\r\n\t\t\t#define PLF_NOEXCEPT throw()\r\n\t\t#endif\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4\r\n\t\t\t#define PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\t#endif\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4\r\n\t\t\t#define PLF_ALIGNMENT_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GNUC__ >= 5 // GCC v4.9 and below do not support std::is_trivially_copyable\r\n\t\t\t#define PLF_TYPE_TRAITS_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GNUC__ > 6\r\n\t\t\t#define PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\t\t#endif\r\n\t#elif defined(__clang__) && !defined(__GLIBCXX__) && !defined(_LIBCPP_CXX03_LANG)\r\n\t\t#if __clang_major__ >= 3 // clang versions < 3 don't support __has_feature() or traits\r\n\t\t\t#define PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\t\t#define PLF_TYPE_TRAITS_SUPPORT\r\n\r\n\t\t\t#if __has_feature(cxx_alignas) && __has_feature(cxx_alignof)\r\n\t\t\t\t#define PLF_ALIGNMENT_SUPPORT\r\n\t\t\t#endif\r\n\t\t\t#if __has_feature(cxx_noexcept)\r\n\t\t\t\t#define PLF_NOEXCEPT noexcept\r\n\t\t\t\t#define PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\t\t\t#else\r\n\t\t\t\t#define PLF_NOEXCEPT throw()\r\n\t\t\t#endif\r\n\t\t\t#if __has_feature(cxx_rvalue_references) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)\r\n\t\t\t\t#define PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#endif\r\n\t\t\t#if __has_feature(cxx_static_assert)\r\n\t\t\t\t#define PLF_STATIC_ASSERT(check, message) static_assert(check, message)\r\n\t\t\t#else\r\n\t\t\t\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t\t\t#endif\r\n\t\t\t#if __has_feature(cxx_variadic_templates) && !defined(_LIBCPP_HAS_NO_VARIADICS)\r\n\t\t\t\t#define PLF_VARIADICS_SUPPORT\r\n\t\t\t#endif\r\n\t\t\t#if (__clang_major__ == 3 && __clang_minor__ >= 1) || __clang_major__ > 3\r\n\t\t\t\t#define PLF_INITIALIZER_LIST_SUPPORT\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t#elif defined(__GLIBCXX__) // Using another compiler type with libstdc++ - we are assuming full c++11 compliance for compiler - which may not be true\r\n\t\t#if __GLIBCXX__ >= 20080606\r\n\t\t\t#define PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#define PLF_VARIADICS_SUPPORT\r\n\t\t\t#define PLF_STATIC_ASSERT(check, message) static_assert(check, message)\r\n\t\t#else\r\n\t\t\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20090421\r\n\t\t\t#define PLF_INITIALIZER_LIST_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20120322\r\n\t\t\t#define PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\t\t#define PLF_NOEXCEPT noexcept\r\n\t\t#else\r\n\t\t\t#define PLF_NOEXCEPT throw()\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20130322\r\n\t\t\t#define PLF_ALIGNMENT_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20150422 // libstdc++ v4.9 and below do not support std::is_trivially_copyable\r\n\t\t\t#define PLF_TYPE_TRAITS_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20160111\r\n\t\t\t#define PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\t\t#endif\r\n\t#elif defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) // Special case for checking C++11 support with libCPP\r\n\t\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t\t#define PLF_NOEXCEPT throw()\r\n\t\t#if !defined(_LIBCPP_HAS_NO_VARIADICS)\r\n\t\t\t#define PLF_VARIADICS_SUPPORT\r\n\t\t#endif\r\n\t#else // Assume type traits and initializer support for other compilers and standard library implementations\r\n\t\t#define PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t#define PLF_STATIC_ASSERT(check, message) static_assert(check, message)\r\n\t\t#define PLF_VARIADICS_SUPPORT\r\n\t\t#define PLF_TYPE_TRAITS_SUPPORT\r\n\t\t#define PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\t#define PLF_ALIGNMENT_SUPPORT\r\n\t\t#define PLF_INITIALIZER_LIST_SUPPORT\r\n\t\t#define PLF_NOEXCEPT noexcept\r\n\t\t#define PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\t#endif\r\n\r\n\t#if __cplusplus >= 201703L && ((defined(__clang__) && ((__clang_major__ == 3 && __clang_minor__ == 9) || __clang_major__ > 3)) || (defined(__GNUC__) && __GNUC__ >= 7) || (!defined(__clang__) && !defined(__GNUC__))) // assume correct C++17 implementation for non-gcc/clang compilers\r\n\t\t#define PLF_CONSTEXPR constexpr\r\n\t#else\r\n\t\t#define PLF_CONSTEXPR\r\n\t#endif\r\n\r\n\t#if __cplusplus > 201703L && ((defined(__clang__) && (__clang_major__ >= 13)) || (defined(__GNUC__) && __GNUC__ >= 10) || (!defined(__clang__) && !defined(__GNUC__)))\r\n\t\t#define PLF_CPP20_SUPPORT\r\n\t#endif\r\n#else\r\n\t#define PLF_FORCE_INLINE\r\n\t#define PLF_STATIC_ASSERT(check, message) assert(check)\r\n\t#define PLF_NOEXCEPT throw()\r\n\t#define PLF_CONSTEXPR\r\n#endif\r\n\r\n#if defined(PLF_IS_ALWAYS_EQUAL_SUPPORT) && defined(PLF_MOVE_SEMANTICS_SUPPORT) && defined(PLF_ALLOCATOR_TRAITS_SUPPORT) && (__cplusplus >= 201703L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L)))\r\n\t#define PLF_NOEXCEPT_MOVE_ASSIGN(the_allocator) noexcept(std::allocator_traits<the_allocator>::propagate_on_container_move_assignment::value || std::allocator_traits<the_allocator>::is_always_equal::value)\r\n\t#define PLF_NOEXCEPT_SWAP(the_allocator) noexcept(std::allocator_traits<the_allocator>::propagate_on_container_swap::value || std::allocator_traits<the_allocator>::is_always_equal::value)\r\n#else\r\n\t#define PLF_NOEXCEPT_MOVE_ASSIGN(the_allocator)\r\n\t#define PLF_NOEXCEPT_SWAP(the_allocator)\r\n#endif\r\n\r\n#undef PLF_IS_ALWAYS_EQUAL_SUPPORT\r\n\r\n\r\n#ifdef PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\t#define PLF_CONSTRUCT(the_allocator, allocator_instance, location, ...)\tstd::allocator_traits<the_allocator>::construct(allocator_instance, location, __VA_ARGS__)\r\n\t#else\r\n\t\t#define PLF_CONSTRUCT(the_allocator, allocator_instance, location, data)\tstd::allocator_traits<the_allocator>::construct(allocator_instance, location, data)\r\n\t#endif\r\n\r\n\t#define PLF_DESTROY(the_allocator, allocator_instance, location) \t\t\t\tstd::allocator_traits<the_allocator>::destroy(allocator_instance, location)\r\n\t#define PLF_ALLOCATE(the_allocator, allocator_instance, size, hint) \t\t\tstd::allocator_traits<the_allocator>::allocate(allocator_instance, size, hint)\r\n\t#define PLF_DEALLOCATE(the_allocator, allocator_instance, location, size) \tstd::allocator_traits<the_allocator>::deallocate(allocator_instance, location, size)\r\n#else\r\n\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\t#define PLF_CONSTRUCT(the_allocator, allocator_instance, location, ...)\t\t(allocator_instance).construct(location, __VA_ARGS__)\r\n\t#else\r\n\t\t#define PLF_CONSTRUCT(the_allocator, allocator_instance, location, data)\t(allocator_instance).construct(location, data)\r\n\t#endif\r\n\r\n\t#define PLF_DESTROY(the_allocator, allocator_instance, location) \t\t\t\t(allocator_instance).destroy(location)\r\n\t#define PLF_ALLOCATE(the_allocator, allocator_instance, size, hint)\t \t\t(allocator_instance).allocate(size, hint)\r\n\t#define PLF_DEALLOCATE(the_allocator, allocator_instance, location, size)\t(allocator_instance).deallocate(location, size)\r\n#endif\r\n\r\n\r\n\r\n#include <algorithm> // std::fill_n, std::sort\r\n#include <cassert>\t// assert\r\n#include <cstring>\t// memset, memcpy, size_t\r\n#include <limits>  // std::numeric_limits\r\n#include <memory>\t// std::allocator\r\n#include <iterator> // std::bidirectional_iterator_tag, iterator_traits, make_move_iterator, std::distance for range insert\r\n#include <stdexcept> // std::length_error\r\n\r\n\r\n#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t#include <cstddef> // offsetof, used in blank()\r\n\t#include <type_traits> // std::is_trivially_destructible, etc\r\n#endif\r\n\r\n#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t#include <utility> // std::move\r\n#endif\r\n\r\n#ifdef PLF_INITIALIZER_LIST_SUPPORT\r\n\t#include <initializer_list>\r\n#endif\r\n\r\n#ifdef PLF_CPP20_SUPPORT\r\n\t#include <concepts>\r\n#endif\r\n\r\n\r\nnamespace plf\r\n{\r\n\r\n\r\nstruct colony_limits // for use in block_capacity setting/getting functions and constructors\r\n{\r\n\tsize_t min, max;\r\n\tcolony_limits(const size_t minimum, const size_t maximum) PLF_NOEXCEPT : min(minimum), max(maximum) {}\r\n};\r\n\r\n\r\nenum colony_priority { performance, memory_use };\r\n\r\n\r\n\r\ntemplate <class element_type, class allocator_type = std::allocator<element_type>, plf::colony_priority priority = plf::performance> class colony : private allocator_type\t// Empty base class optimisation (EBCO) - inheriting allocator functions\r\n{\r\n\t// Type-switching pattern:\r\n\ttemplate <bool flag, class is_true, class is_false> struct choose;\r\n\r\n\ttemplate <class is_true, class is_false> struct choose<true, is_true, is_false>\r\n\t{\r\n\t\ttypedef is_true type;\r\n\t};\r\n\r\n\ttemplate <class is_true, class is_false> struct choose<false, is_true, is_false>\r\n\t{\r\n\t\ttypedef is_false type;\r\n\t};\r\n\r\n\ttypedef typename choose<priority == plf::performance, unsigned short, unsigned char>::type\t\tskipfield_type; // Note: unsigned short is equivalent to uint_least16_t ie. Using 16-bit unsigned integer in best-case scenario, greater-than-16-bit unsigned integer where platform doesn't support 16-bit types. unsigned char is always == 1 byte, as opposed to uint_8, which may not be\r\n\r\npublic:\r\n\t// Standard container typedefs:\r\n\ttypedef element_type\tvalue_type;\r\n\r\n\t#ifdef PLF_ALIGNMENT_SUPPORT\r\n\t\ttypedef typename std::aligned_storage<sizeof(element_type), (sizeof(element_type) >= (sizeof(skipfield_type) * 2) || alignof(element_type) >= (sizeof(skipfield_type) * 2)) ? alignof(element_type) : (sizeof(skipfield_type) * 2)>::type\taligned_element_type;\r\n\t#else\r\n\t\ttypedef element_type aligned_element_type;\r\n\t#endif\r\n\r\n\t#ifdef PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::size_type\t\t\t\tsize_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::difference_type \tdifference_type;\r\n\t\ttypedef element_type &\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treference;\r\n\t\ttypedef const element_type &\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst_reference;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::pointer \t\t\t\tpointer;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::const_pointer\t\tconst_pointer;\r\n\t#else\r\n\t\ttypedef typename allocator_type::size_type\t\t\tsize_type;\r\n\t\ttypedef typename allocator_type::difference_type\tdifference_type;\r\n\t\ttypedef typename allocator_type::reference\t\t\treference;\r\n\t\ttypedef typename allocator_type::const_reference\tconst_reference;\r\n\t\ttypedef typename allocator_type::pointer\t\t\t\tpointer;\r\n\t\ttypedef typename allocator_type::const_pointer\t\tconst_pointer;\r\n\t#endif\r\n\r\n\r\n\t// Iterator declarations:\r\n\ttemplate <bool is_const> class\t\t\tcolony_iterator;\r\n\ttypedef colony_iterator<false>\t\t\titerator;\r\n\ttypedef colony_iterator<true>\t\t\tconst_iterator;\r\n\tfriend class colony_iterator<false>; // Using above typedef name here is illegal under C++03\r\n\tfriend class colony_iterator<true>;\r\n\r\n\ttemplate <bool r_is_const> class\t\tcolony_reverse_iterator;\r\n\ttypedef colony_reverse_iterator<false>\treverse_iterator;\r\n\ttypedef colony_reverse_iterator<true>\tconst_reverse_iterator;\r\n\tfriend class colony_reverse_iterator<false>;\r\n\tfriend class colony_reverse_iterator<true>;\r\n\r\n\r\n\r\nprivate:\r\n\r\n\t#ifdef PLF_ALIGNMENT_SUPPORT\r\n\t\tstruct alignas(alignof(aligned_element_type)) aligned_allocation_struct\r\n\t\t{\r\n\t\t  char data[alignof(aligned_element_type)]; // Using char as sizeof is always guaranteed to be 1 byte regardless of the number of bits in a byte on given computer, whereas for example, uint8_t would fail on machines where there are more than 8 bits in a byte eg. Texas Instruments C54x DSPs.\r\n\t\t};\r\n\r\n\t\t#define PLF_GROUP_ALIGNED_BLOCK_SIZE(elements_per_group) ((((elements_per_group * (((sizeof(aligned_element_type) >= alignof(aligned_element_type)) ? sizeof(aligned_element_type) : alignof(aligned_element_type)) + sizeof(skipfield_type))) + sizeof(skipfield_type)) + sizeof(aligned_allocation_struct) - 1) / sizeof(aligned_allocation_struct)) // The size of a groups' memory block when expressed in multiples of the value_type's alignment. We also check to see if alignment is larger than sizeof value_type and use alignment size if so.\r\n\t#else\r\n\t\tstruct aligned_allocation_struct\r\n\t\t{\r\n\t\t  char data;\r\n\t\t};\r\n\r\n\t\t#define PLF_GROUP_ALIGNED_BLOCK_SIZE(elements_per_group) ((elements_per_group * (sizeof(aligned_element_type) + sizeof(skipfield_type))) + sizeof(skipfield_type)) // The size of a groups' memory block when expressed in bytes, since no alignment available\r\n\t#endif\r\n\r\n\r\n\t// forward declarations for typedefs below\r\n\tstruct group;\r\n\tstruct item_index_tuple; // for use in sort()\r\n\r\n\r\n\t#ifdef PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<aligned_element_type>\t\taligned_element_allocator_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<group>\t\t\t\t\t\t\tgroup_allocator_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<skipfield_type>\t\t\t\tskipfield_allocator_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<aligned_allocation_struct>\taligned_struct_allocator_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<item_index_tuple>\t\t\t\ttuple_allocator_type;\r\n\t\ttypedef typename std::allocator_traits<allocator_type>::template rebind_alloc<unsigned char>\t\t\t\t\tuchar_allocator_type;\r\n\r\n\t\ttypedef typename std::allocator_traits<aligned_element_allocator_type>::pointer\taligned_pointer_type; // pointer to the overaligned element type, not the original element type\r\n\t\ttypedef typename std::allocator_traits<group_allocator_type>::pointer \t\t\t\tgroup_pointer_type;\r\n\t\ttypedef typename std::allocator_traits<skipfield_allocator_type>::pointer \t\t\tskipfield_pointer_type;\r\n\t\ttypedef typename std::allocator_traits<aligned_struct_allocator_type>::pointer\taligned_struct_pointer_type;\r\n\t\ttypedef typename std::allocator_traits<tuple_allocator_type>::pointer\t\t\t\ttuple_pointer_type;\r\n\t#else\r\n\t\ttypedef typename allocator_type::template rebind<aligned_element_type>::other\t\taligned_element_allocator_type;\t// In case compiler supports alignment but not allocator_traits\r\n\t\ttypedef typename allocator_type::template rebind<group>::other\t\t\t\t\t\t\tgroup_allocator_type;\r\n\t\ttypedef typename allocator_type::template rebind<skipfield_type>::other\t\t\t\tskipfield_allocator_type;\r\n\t\ttypedef typename allocator_type::template rebind<char>::other\t\t\t\t\t\t\taligned_struct_allocator_type;\r\n\t\ttypedef typename allocator_type::template rebind<item_index_tuple>::other\t\t\ttuple_allocator_type;\r\n\t\ttypedef typename allocator_type::template rebind<unsigned char>::other\t\t\t\tuchar_allocator_type;\r\n\r\n\t\ttypedef typename aligned_element_allocator_type::pointer\taligned_pointer_type;\r\n\t\ttypedef typename group_allocator_type::pointer \t\t\t\tgroup_pointer_type;\r\n\t\ttypedef typename skipfield_allocator_type::pointer \t\tskipfield_pointer_type;\r\n\t\ttypedef typename aligned_struct_allocator_type::pointer\taligned_struct_pointer_type;\r\n\t\ttypedef typename tuple_allocator_type::pointer\t\t\t\ttuple_pointer_type;\r\n\t#endif\r\n\r\n\r\n\r\n\t// Colony groups:\r\n\tstruct group : private aligned_struct_allocator_type\t// ebco - inherit allocator functions\r\n\t{\r\n\t\taligned_pointer_type\t\t\t\t\tlast_endpoint; \t\t\t// The address that is one past the highest cell number that's been used so far in this group - does not change with erase command but may change with insert (if no previously-erased locations are available) - is necessary because an iterator cannot access the colony's end_iterator. Most-used variable in colony use (operator ++, --) so first in struct. If the colony has been completely filled at some point, it will be == reinterpret_cast<aligned_pointer_type>(skipfield)\r\n\t\tgroup_pointer_type\t\t\t\t\tnext_group; \t\t\t\t// Next group in the intrusive list of all groups. NULL if no next group\r\n\t\tconst aligned_pointer_type\t\t\telements; \t\t\t\t\t// Element storage\r\n\t\tconst skipfield_pointer_type\t\tskipfield; \t\t\t\t\t// Skipfield storage. The element and skipfield arrays are allocated contiguously in this implementation, hence the skipfield pointer also functions as a 'one-past-end' pointer for the elements array. There will always be one additional skipfield node allocated compared to the number of elements. This is to ensure a faster ++ iterator operation (fewer checks are required when this is present). The extra node is unused and always zero, but checked, and not having it will result in out-of-bounds memory errors.\r\n\t\tgroup_pointer_type\t\t\t\t\tprevious_group; \t\t\t// previous group in the linked list of all groups. NULL if no preceding group\r\n\t\tskipfield_type\t\t\t\t\t\t\tfree_list_head; \t\t\t// The index of the last erased element in the group. The last erased element will, in turn, contain the number of the index of the next erased element, and so on. If this is == maximum skipfield_type value then free_list is empty ie. no erasures have occurred in the group (or if they have, the erased locations have subsequently been reused via insert()).\r\n\t\tconst skipfield_type\t\t\t\t\tcapacity; \t\t\t\t\t// The element capacity of this particular group - can also be calculated from reinterpret_cast<aligned_pointer_type>(group->skipfield) - group->elements, however this space is effectively free due to struct padding and the default sizeof skipfield_type, and calculating it once is cheaper\r\n\t\tskipfield_type\t\t\t\t\t\t\tsize; \t\t\t\t\t\t// indicates total number of active elements in group - changes with insert and erase commands - used to check for empty group in erase function, as an indication to remove the group\r\n\t\tgroup_pointer_type\t\t\t\t\terasures_list_next_group; // The next group in the singly-linked list of groups with erasures ie. with active erased-element free lists\r\n\t\tsize_type\t\t\t\t\t\t\t\tgroup_number; \t\t\t\t// Used for comparison (> < >= <= <=>) iterator operators (used by distance function and user)\r\n\r\n\r\n\t\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\t\tgroup(const skipfield_type elements_per_group, group_pointer_type const previous):\r\n\t\t\t\tlast_endpoint(reinterpret_cast<aligned_pointer_type>(PLF_ALLOCATE(aligned_struct_allocator_type, *this, PLF_GROUP_ALIGNED_BLOCK_SIZE(elements_per_group), (previous == NULL) ? 0 : previous->elements))),\r\n\t\t\t\tnext_group(NULL),\r\n\t\t\t\telements(last_endpoint++),\r\n\t\t\t\tskipfield(reinterpret_cast<skipfield_pointer_type>(elements + elements_per_group)),\r\n\t\t\t\tprevious_group(previous),\r\n\t\t\t\tfree_list_head(std::numeric_limits<skipfield_type>::max()),\r\n\t\t\t\tcapacity(elements_per_group),\r\n\t\t\t\tsize(1),\r\n\t\t\t\terasures_list_next_group(NULL),\r\n\t\t\t\tgroup_number((previous == NULL) ? 0 : previous->group_number + 1u)\r\n\t\t\t{\r\n\t\t\t\t// Static casts to unsigned int from short not necessary as C++ automatically promotes lesser types for arithmetic purposes.\r\n\t\t\t\tstd::memset(&*skipfield, 0, sizeof(skipfield_type) * (static_cast<size_type>(elements_per_group) + 1u)); // &* to avoid problems with non-trivial pointers\r\n\t\t\t}\r\n\r\n\t\t#else\r\n\t\t\t// 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. So to avoid running out of memory (and losing performance) from allocating the same block twice, we're allocating in the 'copy' constructor.\r\n\t\t\tgroup(const skipfield_type elements_per_group, group_pointer_type const previous) PLF_NOEXCEPT:\r\n\t\t\t\telements(NULL),\r\n\t\t\t\tskipfield(NULL),\r\n\t\t\t\tprevious_group(previous),\r\n\t\t\t\tcapacity(elements_per_group)\r\n\t\t\t{}\r\n\r\n\r\n\r\n\t\t\t// Not a real copy constructor ie. actually a constructor. Only used for allocator.construct in C++03 for reasons stated above:\r\n\t\t\tgroup(const group &source):\r\n\t\t\t\taligned_struct_allocator_type(source),\r\n\t\t\t\tlast_endpoint(reinterpret_cast<aligned_pointer_type>(PLF_ALLOCATE(aligned_struct_allocator_type, *this, PLF_GROUP_ALIGNED_BLOCK_SIZE(source.capacity), (source.previous_group == NULL) ? 0 : source.previous_group->elements))),\r\n\t\t\t\tnext_group(NULL),\r\n\t\t\t\telements(last_endpoint++),\r\n\t\t\t\tskipfield(reinterpret_cast<skipfield_pointer_type>(elements + source.capacity)),\r\n\t\t\t\tprevious_group(source.previous_group),\r\n\t\t\t\tfree_list_head(std::numeric_limits<skipfield_type>::max()),\r\n\t\t\t\tcapacity(source.capacity),\r\n\t\t\t\tsize(1),\r\n\t\t\t\terasures_list_next_group(NULL),\r\n\t\t\t\tgroup_number((source.previous_group == NULL) ? 0 : source.previous_group->group_number + 1u)\r\n\t\t\t{\r\n\t\t\t\tstd::memset(&*skipfield, 0, sizeof(skipfield_type) * (static_cast<size_type>(capacity) + 1u));\r\n\t\t\t}\r\n\t\t#endif\r\n\r\n\r\n\r\n\t\tvoid reset(const skipfield_type increment, const group_pointer_type next, const group_pointer_type previous, const size_type group_num) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tlast_endpoint = elements + increment;\r\n\t\t\tnext_group = next;\r\n\t\t\tfree_list_head = std::numeric_limits<skipfield_type>::max();\r\n\t\t\tprevious_group = previous;\r\n\t\t\tsize = increment;\r\n\t\t\terasures_list_next_group = NULL;\r\n\t\t\tgroup_number = group_num;\r\n\r\n\t\t\tstd::memset(&*skipfield, 0, sizeof(skipfield_type) * static_cast<size_type>(capacity)); // capacity + 1 is not necessary here as the end skipfield is never written to after initialization\r\n\t\t}\r\n\r\n\r\n\r\n\t\t~group() PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\t// Null check not necessary (for copied group as above) as delete will also perform a null check.\r\n\t\t\tPLF_DEALLOCATE(aligned_struct_allocator_type, *this, reinterpret_cast<aligned_struct_pointer_type>(elements), PLF_GROUP_ALIGNED_BLOCK_SIZE(capacity));\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\npublic:\r\n\r\n\r\n\t// Iterators:\r\n\ttemplate <bool is_const> class colony_iterator\r\n\t{\r\n\tprivate:\r\n\t\tgroup_pointer_type\t\tgroup_pointer;\r\n\t\taligned_pointer_type\t\telement_pointer;\r\n\t\tskipfield_pointer_type\tskipfield_pointer;\r\n\r\n\tpublic:\r\n\t\ttypedef std::bidirectional_iterator_tag \titerator_category;\r\n\t\ttypedef typename colony::value_type \t\tvalue_type;\r\n\t\ttypedef typename colony::difference_type \tdifference_type;\r\n\t\ttypedef typename choose<is_const, typename colony::const_pointer, typename colony::pointer>::type\t\tpointer;\r\n\t\ttypedef typename choose<is_const, typename colony::const_reference, typename colony::reference>::type\treference;\r\n\r\n\t\tfriend class colony;\r\n\t\tfriend class colony_reverse_iterator<false>;\r\n\t\tfriend class colony_reverse_iterator<true>;\r\n\r\n\r\n\r\n\t\tinline colony_iterator & operator = (const colony_iterator &source) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tgroup_pointer = source.group_pointer;\r\n\t\t\telement_pointer = source.element_pointer;\r\n\t\t\tskipfield_pointer = source.skipfield_pointer;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_iterator & operator = (const colony_iterator<!is_const> &source) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tgroup_pointer = source.group_pointer;\r\n\t\t\telement_pointer = source.element_pointer;\r\n\t\t\tskipfield_pointer = source.skipfield_pointer;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t// Move assignment - only really necessary if the allocator uses non-standard ie. \"smart\" pointers\r\n\t\t\tinline colony_iterator & operator = (colony_iterator &&source) PLF_NOEXCEPT\r\n\t\t\t{\r\n\t\t\t\tassert(&source != this);\r\n\t\t\t\tgroup_pointer = std::move(source.group_pointer);\r\n\t\t\t\telement_pointer = std::move(source.element_pointer);\r\n\t\t\t\tskipfield_pointer = std::move(source.skipfield_pointer);\r\n\t\t\t\treturn *this;\r\n\t\t\t}\r\n\r\n\r\n\r\n\t\t\tinline colony_iterator & operator = (colony_iterator<!is_const> &&source) PLF_NOEXCEPT\r\n\t\t\t{\r\n\t\t\t\tgroup_pointer = std::move(source.group_pointer);\r\n\t\t\t\telement_pointer = std::move(source.element_pointer);\r\n\t\t\t\tskipfield_pointer = std::move(source.skipfield_pointer);\r\n\t\t\t\treturn *this;\r\n\t\t\t}\r\n\t\t#endif\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator == (const colony_iterator &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (element_pointer == rh.element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator == (const colony_iterator<!is_const> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (element_pointer == rh.element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator != (const colony_iterator &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (element_pointer != rh.element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator != (const colony_iterator<!is_const> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (element_pointer != rh.element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE reference operator * () const // may cause exception with uninitialized iterator\r\n\t\t{\r\n\t\t\treturn *(reinterpret_cast<pointer>(element_pointer));\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE pointer operator -> () const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn reinterpret_cast<pointer>(element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n#if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) && _MSC_VER <= 1600 // MSVC 2010 needs a bit of a helping hand when it comes to optimizing\r\n\t\tinline PLF_FORCE_INLINE colony_iterator & operator ++ ()\r\n#else\r\n\t\tcolony_iterator & operator ++ ()\r\n#endif\r\n\t\t{\r\n\t\t\tassert(group_pointer != NULL); // covers uninitialised colony_iterator\r\n\t\t\tskipfield_type skip = *(++skipfield_pointer);\r\n\r\n\t\t\tif ((element_pointer += static_cast<size_type>(skip) + 1u) == group_pointer->last_endpoint && group_pointer->next_group != NULL) // ie. beyond end of current memory block. Second condition allows iterator to reach end(), which may be 1 past end of block, if block has been fully used and another block is not allocated\r\n\t\t\t{\r\n\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\t\t\t\tconst aligned_pointer_type elements = group_pointer->elements;\r\n\t\t\t\tconst skipfield_pointer_type skipfield = group_pointer->skipfield;\r\n\t\t\t\tskip = *skipfield;\r\n\t\t\t\telement_pointer = elements + skip;\r\n\t\t\t\tskipfield_pointer = skipfield;\r\n\t\t\t}\r\n\r\n\t\t\tskipfield_pointer += skip;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_iterator operator ++(int)\r\n\t\t{\r\n\t\t\tconst colony_iterator copy(*this);\r\n\t\t\t++*this;\r\n\t\t\treturn copy;\r\n\t\t}\r\n\r\n\r\n\r\n\tpublic:\r\n\r\n\t\tcolony_iterator & operator -- ()\r\n\t\t{\r\n\t\t\tassert(group_pointer != NULL);\r\n\r\n\t\t\tif (element_pointer != group_pointer->elements) // ie. not already at beginning of group\r\n\t\t\t{\r\n\t\t\t\tconst skipfield_type skip = *(--skipfield_pointer);\r\n\t\t\t\tskipfield_pointer -= skip;\r\n\r\n\t\t\t\tif ((element_pointer -= static_cast<size_type>(skip) + 1u) != group_pointer->elements - 1) // ie. iterator was not already at beginning of colony (with some previous consecutive deleted elements), and skipfield does not takes us into the previous group)\r\n\t\t\t\t{\r\n\t\t\t\t\treturn *this;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\t\t\tconst skipfield_pointer_type skipfield = group_pointer->skipfield + group_pointer->capacity - 1;\r\n\t\t\tconst skipfield_type skip = *skipfield;\r\n\t\t\telement_pointer = (reinterpret_cast<colony::aligned_pointer_type>(group_pointer->skipfield) - 1) - skip;\r\n\t\t\tskipfield_pointer = skipfield - skip;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_iterator operator -- (int)\r\n\t\t{\r\n\t\t\tconst colony_iterator copy(*this);\r\n\t\t\t--*this;\r\n\t\t\treturn copy;\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator > (const colony_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn ((group_pointer == rh.group_pointer) & (element_pointer > rh.element_pointer)) || (group_pointer != rh.group_pointer && group_pointer->group_number > rh.group_pointer->group_number);\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator < (const colony_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn rh > *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator >= (const colony_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn !(rh > *this);\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator <= (const colony_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn !(*this > rh);\r\n\t\t}\r\n\r\n\r\n\r\n\t\t#ifdef PLF_CPP20_SUPPORT\r\n\t\t\ttemplate <bool is_const_it>\r\n\t\t\tinline int operator <=> (const colony_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t \t\t{\r\n\t \t\t\treturn (element_pointer == rh.element_pointer) ? 0 : ((*this > rh) ? 1 : -1);\r\n\t \t\t}\r\n\t \t#endif\r\n\r\n\r\n\r\n\t\tcolony_iterator() PLF_NOEXCEPT: group_pointer(NULL), element_pointer(NULL), skipfield_pointer(NULL)\t{}\r\n\r\n\r\n\r\n\tprivate:\r\n\t\t// Used by cend(), erase() etc:\r\n\t\tcolony_iterator(const group_pointer_type group_p, const aligned_pointer_type element_p, const skipfield_pointer_type skipfield_p) PLF_NOEXCEPT: group_pointer(group_p), element_pointer(element_p), skipfield_pointer(skipfield_p) {}\r\n\r\n\r\n\tpublic:\r\n\r\n\t\t// Friend functions:\r\n\r\n\t\ttemplate <class distance_type>\r\n\t\tfriend inline void advance(colony_iterator &it, distance_type distance)\r\n\t\t{\r\n\t\t\tit.advance(static_cast<difference_type>(distance));\r\n\t\t}\r\n\r\n\r\n\r\n\t\tfriend inline colony_iterator next(const colony_iterator &it, const difference_type distance)\r\n\t\t{\r\n\t\t\tcolony_iterator return_iterator(it);\r\n\t\t\treturn_iterator.advance(static_cast<difference_type>(distance));\r\n\t\t\treturn return_iterator;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tfriend inline colony_iterator prev(const colony_iterator &it, const difference_type distance)\r\n\t\t{\r\n\t\t\tcolony_iterator return_iterator(it);\r\n\t\t\treturn_iterator.advance(-(static_cast<difference_type>(distance)));\r\n\t\t\treturn return_iterator;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tfriend inline typename colony_iterator::difference_type distance(const colony_iterator &first, const colony_iterator &last)\r\n\t\t{\r\n\t\t\treturn first.distance(last);\r\n\t\t}\r\n\r\n\r\n\r\n\tprivate:\r\n\r\n\t\t// Advance implementation:\r\n\r\n\t\tvoid advance(difference_type distance) // Cannot be noexcept due to the possibility of an uninitialized iterator\r\n\t\t{\r\n\t\t\tassert(group_pointer != NULL); // covers uninitialized colony_iterator && empty group\r\n\r\n\t\t\t// Now, run code based on the nature of the distance type - negative, positive or zero:\r\n\t\t\tif (distance > 0) // ie. +=\r\n\t\t\t{\r\n\t\t\t\t// Code explanation:\r\n\t\t\t\t// For the initial state of the iterator, we don't know how what elements have been erased before that element in that group.\r\n\t\t\t\t// So for the first group, we follow the following logic:\r\n\t\t\t\t// 1. If no elements have been erased in the group, we do simple addition to progress either to within the group (if the distance is small enough) or the end of the group and subtract from distance accordingly.\r\n\t\t\t\t// 2. If any of the first group elements have been erased, we manually iterate, as we don't know whether the erased elements occur before or after the initial iterator position, and we subtract 1 from the distance amount each time. Iteration continues until either distance becomes zero, or we reach the end of the group.\r\n\r\n\t\t\t\t// For all subsequent groups, we follow this logic:\r\n\t\t\t\t// 1. If distance is larger than the total number of non-erased elements in a group, we skip that group and subtract the number of elements in that group from distance\r\n\t\t\t\t// 2. If distance is smaller than the total number of non-erased elements in a group, then:\r\n\t\t\t\t//\t  a. if there're no erased elements in the group we simply add distance to group->elements to find the new location for the iterator\r\n\t\t\t\t//\t  b. if there are erased elements in the group, we manually iterate and subtract 1 from distance on each iteration, until the new iterator location is found ie. distance = 0\r\n\r\n\t\t\t\t// Note: incrementing element_pointer is avoided until necessary to avoid needless calculations\r\n\r\n\t\t\t\tassert(!(element_pointer == group_pointer->last_endpoint && group_pointer->next_group == NULL)); // Check that we're not already at end()\r\n\r\n\t\t\t\t// Special case for initial element pointer and initial group (we don't know how far into the group the element pointer is)\r\n\t\t\t\tif (element_pointer != group_pointer->elements + *(group_pointer->skipfield)) // ie. != first non-erased element in group\r\n\t\t\t\t{\r\n\t\t\t\t\tconst difference_type distance_from_end = static_cast<difference_type>(group_pointer->last_endpoint - element_pointer);\r\n\r\n\t\t\t\t\tif (group_pointer->size == static_cast<skipfield_type>(distance_from_end)) // ie. if there are no erasures in the group (using endpoint - elements_start to determine number of elements in group just in case this is the last group of the colony, in which case group->last_endpoint != group->elements + group->capacity)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (distance < distance_from_end)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer += distance;\r\n\t\t\t\t\t\t\tskipfield_pointer += distance;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (group_pointer->next_group == NULL) // either we've reached end() or gone beyond it, so bound to end()\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->last_endpoint;\r\n\t\t\t\t\t\t\tskipfield_pointer += distance_from_end;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdistance -= distance_from_end;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_pointer_type endpoint = skipfield_pointer + distance_from_end;\r\n\r\n\t\t\t\t\t\twhile(true)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t++skipfield_pointer;\r\n\t\t\t\t\t\t\tskipfield_pointer += *skipfield_pointer;\r\n\t\t\t\t\t\t\t--distance;\r\n\r\n\t\t\t\t\t\t\tif (skipfield_pointer == endpoint)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse if (distance == 0)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (group_pointer->next_group == NULL) // either we've reached end() or gone beyond it, so bound to end()\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->last_endpoint;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\r\n\t\t\t\t\tif (distance == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Intermediary groups - at the start of this code block and the subsequent block, the position of the iterator is assumed to be the first non-erased element in the current group:\r\n\t\t\t\twhile (static_cast<difference_type>(group_pointer->size) <= distance)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->next_group == NULL) // either we've reached end() or gone beyond it, so bound to end()\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->last_endpoint;\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + (group_pointer->last_endpoint - group_pointer->elements);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if ((distance -= group_pointer->size) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Final group (if not already reached):\r\n\t\t\t\tif (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // No erasures in this group, use straight pointer addition\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = group_pointer->elements + distance;\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + distance;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse\t // ie. size > distance - safe to ignore endpoint check condition while incrementing:\r\n\t\t\t\t{\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer += *skipfield_pointer;\r\n\t\t\t\t\t} while(--distance != 0);\r\n\r\n\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telse if (distance < 0) // for negative change\r\n\t\t\t{\r\n\t\t\t\t// Code logic is very similar to += above\r\n\t\t\t\tassert(!((element_pointer == group_pointer->elements + *(group_pointer->skipfield)) && group_pointer->previous_group == NULL)); // check that we're not already at begin()\r\n\t\t\t\tdistance = -distance;\r\n\r\n\t\t\t\t// Special case for initial element pointer and initial group (we don't know how far into the group the element pointer is)\r\n\t\t\t\tif (element_pointer != group_pointer->last_endpoint) // ie. != end()\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // ie. no prior erasures have occurred in this group\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst difference_type distance_from_beginning = static_cast<difference_type>(element_pointer - group_pointer->elements);\r\n\r\n\t\t\t\t\t\tif (distance <= distance_from_beginning)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer -= distance;\r\n\t\t\t\t\t\t\tskipfield_pointer -= distance;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (group_pointer->previous_group == NULL) // ie. we've gone before begin(), so bound to begin()\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->elements;\r\n\t\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdistance -= distance_from_beginning;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_pointer_type beginning_point = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\r\n\t\t\t\t\t\twhile(skipfield_pointer != beginning_point)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t--skipfield_pointer;\r\n\t\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\r\n\t\t\t\t\t\t\tif (--distance == 0)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (group_pointer->previous_group == NULL)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield); // This is first group, so bound to begin() (just in case final decrement took us before begin())\r\n\t\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Intermediary groups - at the start of this code block and the subsequent block, the position of the iterator is assumed to be either the first non-erased element in the next group over, or end():\r\n\t\t\t\twhile(static_cast<difference_type>(group_pointer->size) < distance)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->previous_group == NULL) // we've gone beyond begin(), so bound to it\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdistance -= group_pointer->size;\r\n\t\t\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Final group (if not already reached):\r\n\t\t\t\tif (static_cast<difference_type>(group_pointer->size) == distance)\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse if (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // ie. no erased elements in this group\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = reinterpret_cast<aligned_pointer_type>(group_pointer->skipfield) - distance;\r\n\t\t\t\t\tskipfield_pointer = (group_pointer->skipfield + group_pointer->capacity) - distance;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse // ie. no more groups to traverse but there are erased elements in this group\r\n\t\t\t\t{\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + group_pointer->capacity;\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t--skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\t\t\t\t\t} while(--distance != 0);\r\n\r\n\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Only distance == 0 reaches here\r\n\t\t}\r\n\r\n\r\n\r\n\t\t// distance implementation:\r\n\r\n\t\tdifference_type distance(const colony_iterator &last) const\r\n\t\t{\r\n\t\t\t// Code logic:\r\n\t\t\t// If iterators are the same, return 0\r\n\t\t\t// Otherwise, find which iterator is later in colony, copy that to iterator2. Copy the lower to iterator1.\r\n\t\t\t// If they are not pointing to elements in the same group, process the intermediate groups and add distances,\r\n\t\t\t// skipping manual incrementation in all but the initial and final groups.\r\n\t\t\t// In the initial and final groups, manual incrementation must be used to calculate distance, if there have been no prior erasures in those groups.\r\n\t\t\t// If there are no prior erasures in either of those groups, we can use pointer arithmetic to calculate the distances for those groups.\r\n\r\n\t\t\tassert(!(group_pointer == NULL) && !(last.group_pointer == NULL));  // Check that they are initialized\r\n\r\n\t\t\tif (last.element_pointer == element_pointer)\r\n\t\t\t{\r\n\t\t\t\treturn 0;\r\n\t\t\t}\r\n\r\n\t\t\tdifference_type distance = 0;\r\n\t\t\tcolony_iterator iterator1 = *this, iterator2 = last;\r\n\t\t\tconst bool swap = iterator1 > iterator2;\r\n\r\n\t\t\tif (swap) // Less common case\r\n\t\t\t{\r\n\t\t\t\titerator1 = last;\r\n\t\t\t\titerator2 = *this;\r\n\t\t\t}\r\n\r\n\t\t\tif (iterator1.group_pointer != iterator2.group_pointer) // if not in same group, process intermediate groups\r\n\t\t\t{\r\n\t\t\t\t// Process initial group:\r\n\t\t\t\tif (iterator1.group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // If no prior erasures have occured in this group we can do simple addition\r\n\t\t\t\t{\r\n\t\t\t\t\tdistance += static_cast<difference_type>(iterator1.group_pointer->last_endpoint - iterator1.element_pointer);\r\n\t\t\t\t}\r\n\t\t\t\telse if (iterator1.element_pointer == iterator1.group_pointer->elements + *(iterator1.group_pointer->skipfield)) // ie. element is at start of group - rare case\r\n\t\t\t\t{\r\n\t\t\t\t\tdistance += static_cast<difference_type>(iterator1.group_pointer->size);\r\n\t\t\t\t}\r\n\t\t\t\telse // Manually iterate to find distance to end of group:\r\n\t\t\t\t{\r\n\t\t\t\t\tconst skipfield_pointer_type endpoint = iterator1.skipfield_pointer + (iterator1.group_pointer->last_endpoint - iterator1.element_pointer);\r\n\r\n\t\t\t\t\twhile (iterator1.skipfield_pointer != endpoint)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++iterator1.skipfield_pointer;\r\n\t\t\t\t\t\titerator1.skipfield_pointer += *iterator1.skipfield_pointer;\r\n\t\t\t\t\t\t++distance;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Process all other intermediate groups:\r\n\t\t\t\titerator1.group_pointer = iterator1.group_pointer->next_group;\r\n\r\n\t\t\t\twhile (iterator1.group_pointer != iterator2.group_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\tdistance += static_cast<difference_type>(iterator1.group_pointer->size);\r\n\t\t\t\t\titerator1.group_pointer = iterator1.group_pointer->next_group;\r\n\t\t\t\t}\r\n\r\n\t\t\t\titerator1.skipfield_pointer = iterator1.group_pointer->skipfield;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tif (iterator2.group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // ie. no erasures in this group, direct subtraction is possible\r\n\t\t\t{\r\n\t\t\t\tdistance += iterator2.skipfield_pointer - iterator1.skipfield_pointer;\r\n\t\t\t}\r\n\t\t\telse if (iterator2.group_pointer->last_endpoint - 1 >= iterator2.element_pointer || iterator2.element_pointer + *(iterator2.skipfield_pointer + 1) == iterator2.group_pointer->last_endpoint) // ie. if iterator2 is .end() or the last element in the block\r\n\t\t\t{\r\n\t\t\t\tdistance += static_cast<difference_type>(iterator2.group_pointer->size) - (iterator2.group_pointer->last_endpoint - iterator2.element_pointer);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\twhile (iterator1.skipfield_pointer != iterator2.skipfield_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\t++iterator1.skipfield_pointer;\r\n\t\t\t\t\titerator1.skipfield_pointer += *iterator1.skipfield_pointer;\r\n\t\t\t\t\t++distance;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\r\n\t\t\tif (swap)\r\n\t\t\t{\r\n\t\t\t\tdistance = -distance;\r\n\t\t\t}\r\n\r\n\t\t\treturn distance;\r\n\t\t}\r\n\r\n\r\n\tpublic:\r\n\r\n\t\tinline colony_iterator (const colony_iterator &source) PLF_NOEXCEPT:\r\n\t\t\tgroup_pointer(source.group_pointer),\r\n\t\t\telement_pointer(source.element_pointer),\r\n\t\t\tskipfield_pointer(source.skipfield_pointer)\r\n\t\t{}\r\n\r\n\r\n\t\tinline colony_iterator(const colony_iterator<!is_const> &source) PLF_NOEXCEPT:\r\n\t\t\tgroup_pointer(source.group_pointer),\r\n\t\t\telement_pointer(source.element_pointer),\r\n\t\t\tskipfield_pointer(source.skipfield_pointer)\r\n\t\t{}\r\n\r\n\r\n\r\n\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t// move constructors\r\n\t\t\tinline colony_iterator(colony_iterator &&source) PLF_NOEXCEPT:\r\n\t\t\t\tgroup_pointer(std::move(source.group_pointer)),\r\n\t\t\t\telement_pointer(std::move(source.element_pointer)),\r\n\t\t\t\tskipfield_pointer(std::move(source.skipfield_pointer))\r\n\t\t\t{}\r\n\r\n\r\n\t\t\tinline colony_iterator(colony_iterator<!is_const> &&source) PLF_NOEXCEPT:\r\n\t\t\t\tgroup_pointer(std::move(source.group_pointer)),\r\n\t\t\t\telement_pointer(std::move(source.element_pointer)),\r\n\t\t\t\tskipfield_pointer(std::move(source.skipfield_pointer))\r\n\t\t\t{}\r\n\t\t#endif\r\n\r\n\t}; // colony_iterator\r\n\r\n\r\n\r\n\r\n\r\n\t// Reverse iterators:\r\n\r\n\ttemplate <bool r_is_const> class colony_reverse_iterator\r\n\t{\r\n\tprivate:\r\n\t\titerator it;\r\n\r\n\tpublic:\r\n\t\ttypedef std::bidirectional_iterator_tag \titerator_category;\r\n\t\ttypedef typename colony::value_type \t\tvalue_type;\r\n\t\ttypedef typename colony::difference_type \tdifference_type;\r\n\t\ttypedef typename choose<r_is_const, typename colony::const_pointer, typename colony::pointer>::type\t\tpointer;\r\n\t\ttypedef typename choose<r_is_const, typename colony::const_reference, typename colony::reference>::type\treference;\r\n\r\n\t\tfriend class colony;\r\n\r\n\r\n\t\tinline colony_reverse_iterator& operator = (const colony_reverse_iterator &source) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tit = source.it;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_reverse_iterator& operator = (const colony_reverse_iterator<!r_is_const> &source) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tit = source.it;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline colony_reverse_iterator& operator = (const colony_iterator<is_const_it> &source) PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tit = source;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t// move assignment\r\n\t\t\tinline colony_reverse_iterator& operator = (colony_reverse_iterator &&source) PLF_NOEXCEPT\r\n\t\t\t{\r\n\t\t\t\tassert(&source != this);\r\n\t\t\t\tit = std::move(source.it);\r\n\t\t\t\treturn *this;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tinline colony_reverse_iterator& operator = (colony_reverse_iterator<!r_is_const> &&source) PLF_NOEXCEPT\r\n\t\t\t{\r\n\t\t\t\tit = std::move(source.it);\r\n\t\t\t\treturn *this;\r\n\t\t\t}\r\n\t\t#endif\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator == (const colony_reverse_iterator &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (it == rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator == (const colony_reverse_iterator<!r_is_const> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (it == rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator != (const colony_reverse_iterator &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (it != rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE bool operator != (const colony_reverse_iterator<!r_is_const> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (it != rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE reference operator * () const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn *(reinterpret_cast<pointer>(it.element_pointer));\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE pointer * operator -> () const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn reinterpret_cast<pointer>(it.element_pointer);\r\n\t\t}\r\n\r\n\r\n\r\n\t\t// In this case we have to redefine the algorithm, rather than using the internal iterator's -- operator, in order for the reverse_iterator to be allowed to reach rend() ie. begin_iterator - 1\r\n\t\tcolony_reverse_iterator & operator ++ ()\r\n\t\t{\r\n\t\t\tcolony::group_pointer_type &group_pointer = it.group_pointer;\r\n\t\t\tcolony::aligned_pointer_type &element_pointer = it.element_pointer;\r\n\t\t\tcolony::skipfield_pointer_type &skipfield_pointer = it.skipfield_pointer;\r\n\r\n\t\t\tassert(group_pointer != NULL);\r\n\r\n\t\t\tif (element_pointer != group_pointer->elements) // ie. not already at beginning of group\r\n\t\t\t{\r\n\t\t\t\telement_pointer -= static_cast<size_type>(*(--skipfield_pointer)) + 1u;\r\n\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\r\n\t\t\t\tif (!(element_pointer == group_pointer->elements - 1 && group_pointer->previous_group == NULL)) // ie. iterator is not == rend()\r\n\t\t\t\t{\r\n\t\t\t\t\treturn *this;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (group_pointer->previous_group != NULL) // ie. not first group in colony\r\n\t\t\t{\r\n\t\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\t\t\t\tskipfield_pointer = group_pointer->skipfield + group_pointer->capacity - 1;\r\n\t\t\t\telement_pointer = (reinterpret_cast<colony::aligned_pointer_type>(group_pointer->skipfield) - 1) - *skipfield_pointer;\r\n\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\t\t\t}\r\n\t\t\telse // necessary so that reverse_iterator can end up == rend(), if we were already at first element in colony\r\n\t\t\t{\r\n\t\t\t\t--element_pointer;\r\n\t\t\t\t--skipfield_pointer;\r\n\t\t\t}\r\n\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_reverse_iterator operator ++ (int)\r\n\t\t{\r\n\t\t\tconst colony_reverse_iterator copy(*this);\r\n\t\t\t++*this;\r\n\t\t\treturn copy;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline PLF_FORCE_INLINE colony_reverse_iterator & operator -- ()\r\n\t\t{\r\n\t\t\t++it;\r\n\t\t\treturn *this;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline colony_reverse_iterator operator -- (int)\r\n\t\t{\r\n\t\t\tconst colony_reverse_iterator copy(*this);\r\n\t\t\t--*this;\r\n\t\t\treturn copy;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tinline typename colony::iterator base() const\r\n\t\t{\r\n\t\t\treturn ++(typename colony::iterator(it));\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator > (const colony_reverse_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (rh.it > it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator < (const colony_reverse_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn (it > rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator >= (const colony_reverse_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn !(it > rh.it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <bool is_const_it>\r\n\t\tinline bool operator <= (const colony_reverse_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn !(rh.it > it);\r\n\t\t}\r\n\r\n\r\n\r\n\t\t#ifdef PLF_CPP20_SUPPORT\r\n\t\t\ttemplate <bool is_const_it>\r\n\t \t\tinline int operator <=> (const colony_reverse_iterator<is_const_it> &rh) const PLF_NOEXCEPT\r\n\t \t\t{\r\n\t \t\t\treturn (rh.it <=> it);\r\n\t \t\t}\r\n\t \t#endif\r\n\r\n\r\n\r\n\t\tcolony_reverse_iterator () PLF_NOEXCEPT\r\n\t\t{}\r\n\r\n\r\n\r\n\t\tcolony_reverse_iterator (const colony_reverse_iterator &source) PLF_NOEXCEPT:\r\n\t\t\tit(source.it)\r\n\t\t{}\r\n\r\n\r\n\r\n\t\tcolony_reverse_iterator (const colony_reverse_iterator<!r_is_const> &source) PLF_NOEXCEPT:\r\n\t\t\tit(source.it)\r\n\t\t{}\r\n\r\n\r\n\r\n\t\ttemplate<bool is_const>\r\n\t\texplicit colony_reverse_iterator (const colony_iterator<is_const> &source) PLF_NOEXCEPT:\r\n\t\t\tit(source)\r\n\t\t{}\r\n\r\n\r\n\r\n\r\n\tprivate:\r\n\t\t// Used by rend(), etc:\r\n\t\tcolony_reverse_iterator(const group_pointer_type group_p, const aligned_pointer_type element_p, const skipfield_pointer_type skipfield_p) PLF_NOEXCEPT: it(group_p, element_p, skipfield_p) {}\r\n\r\n\r\n\r\n\tpublic:\r\n\t\t// Friend functions:\r\n\r\n\t\ttemplate <class distance_type>\r\n\t\tfriend inline void advance(colony_reverse_iterator &it, distance_type distance)\r\n\t\t{\r\n\t\t\tit.advance(static_cast<difference_type>(distance));\r\n\t\t}\r\n\r\n\r\n\r\n\t\tfriend inline colony_reverse_iterator next(const colony_reverse_iterator &it, const difference_type distance)\r\n\t\t{\r\n\t\t\tcolony_reverse_iterator return_iterator(it);\r\n\t\t\treturn_iterator.advance(static_cast<difference_type>(distance));\r\n\t\t\treturn return_iterator;\r\n\t\t}\r\n\r\n\r\n\r\n\t\ttemplate <class distance_type>\r\n\t\tfriend inline colony_reverse_iterator prev(const colony_reverse_iterator &it, const difference_type distance)\r\n\t\t{\r\n\t\t\tcolony_reverse_iterator return_iterator(it);\r\n\t\t\treturn_iterator.advance(-(static_cast<difference_type>(distance)));\r\n\t\t\treturn return_iterator;\r\n\t\t}\r\n\r\n\r\n\r\n\t\tfriend inline typename colony_reverse_iterator::difference_type distance(const colony_reverse_iterator &first, const colony_reverse_iterator &last)\r\n\t\t{\r\n\t\t\treturn first.distance(last);\r\n\t\t}\r\n\r\n\r\n\r\n\t\t// distance implementation:\r\n\r\n\t\tinline difference_type distance(const colony_reverse_iterator &last) const\r\n\t\t{\r\n\t\t\treturn last.it.distance(it);\r\n\t\t}\r\n\r\n\r\n\r\n\tprivate:\r\n\r\n\t\t// Advance for reverse_iterator and const_reverse_iterator - this needs to be implemented slightly differently to forward-iterator's advance, as it needs to be able to reach rend() (ie. begin() - 1) and to be bounded by rbegin():\r\n\t\tvoid advance(difference_type distance) // could cause exception if iterator is uninitialized\r\n\t\t{\r\n\t\t\tgroup_pointer_type &group_pointer = it.group_pointer;\r\n\t\t\taligned_pointer_type &element_pointer = it.element_pointer;\r\n\t\t\tskipfield_pointer_type &skipfield_pointer = it.skipfield_pointer;\r\n\r\n\t\t\tassert(element_pointer != NULL);\r\n\r\n\t\t\tif (distance > 0)\r\n\t\t\t{\r\n\t\t\t\tassert(!(element_pointer == group_pointer->elements - 1 && group_pointer->previous_group == NULL)); // Check that we're not already at rend()\r\n\t\t\t\t// Special case for initial element pointer and initial group (we don't know how far into the group the element pointer is)\r\n\t\t\t\t// Since a reverse_iterator cannot == last_endpoint (ie. before rbegin()) we don't need to check for that like with iterator\r\n\t\t\t\tif (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\tconst difference_type distance_from_beginning = element_pointer - group_pointer->elements;\r\n\r\n\t\t\t\t\tif (distance <= distance_from_beginning)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer -= distance;\r\n\t\t\t\t\t\tskipfield_pointer -= distance;\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (group_pointer->previous_group == NULL) // Either we've reached rend() or gone beyond it, so bound to rend()\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements - 1;\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield - 1;\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tdistance -= distance_from_beginning;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tconst skipfield_pointer_type beginning_point = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\r\n\t\t\t\t\twhile(skipfield_pointer != beginning_point)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t--skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\r\n\t\t\t\t\t\tif (--distance == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (group_pointer->previous_group == NULL)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements - 1; // If we've reached rend(), bound to that\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield - 1;\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\r\n\r\n\t\t\t\t// Intermediary groups - at the start of this code block and the subsequent block, the position of the iterator is assumed to be the first non-erased element in the next group:\r\n\t\t\t\twhile(static_cast<difference_type>(group_pointer->size) < distance)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->previous_group == NULL) // bound to rend()\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements - 1;\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield - 1;\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdistance -= static_cast<difference_type>(group_pointer->size);\r\n\t\t\t\t\tgroup_pointer = group_pointer->previous_group;\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Final group (if not already reached)\r\n\t\t\t\tif (static_cast<difference_type>(group_pointer->size) == distance)\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse if (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = reinterpret_cast<aligned_pointer_type>(group_pointer->skipfield) - distance;\r\n\t\t\t\t\tskipfield_pointer = (group_pointer->skipfield + group_pointer->capacity) - distance;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + group_pointer->capacity;\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t--skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\t\t\t\t\t} while(--distance != 0);\r\n\r\n\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse if (distance < 0)\r\n\t\t\t{\r\n\t\t\t\tassert(!((element_pointer == (group_pointer->last_endpoint - 1) - *(group_pointer->skipfield + (group_pointer->last_endpoint - group_pointer->elements) - 1)) && group_pointer->next_group == NULL)); // Check that we're not already at rbegin()\r\n\r\n\t\t\t\tif (element_pointer != group_pointer->elements + *(group_pointer->skipfield)) // ie. != first non-erased element in group\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // ie. if there are no erasures in the group\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst difference_type distance_from_end = group_pointer->last_endpoint - element_pointer;\r\n\r\n\t\t\t\t\t\tif (distance < distance_from_end)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer += distance;\r\n\t\t\t\t\t\t\tskipfield_pointer += distance;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (group_pointer->next_group == NULL) // bound to rbegin()\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\telement_pointer = group_pointer->last_endpoint - 1; // no erasures so we don't have to subtract skipfield value as we do below\r\n\t\t\t\t\t\t\tskipfield_pointer += distance_from_end - 1;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdistance -= distance_from_end;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_pointer_type endpoint = skipfield_pointer + (group_pointer->last_endpoint - element_pointer);\r\n\r\n\t\t\t\t\t\twhile(true)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t++skipfield_pointer;\r\n\t\t\t\t\t\t\tskipfield_pointer += *skipfield_pointer;\r\n\t\t\t\t\t\t\t--distance;\r\n\r\n\t\t\t\t\t\t\tif (skipfield_pointer == endpoint)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse if (distance == 0)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (group_pointer->next_group == NULL) // bound to rbegin()\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t--skipfield_pointer;\r\n\t\t\t\t\t\t\telement_pointer = (group_pointer->last_endpoint - 1) - *skipfield_pointer;\r\n\t\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\r\n\t\t\t\t\tif (distance == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Intermediary groups - at the start of this code block and the subsequent block, the position of the iterator is assumed to be the first non-erased element in the current group, as a result of the previous code blocks:\r\n\t\t\t\twhile(static_cast<difference_type>(group_pointer->size) <= distance)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (group_pointer->next_group == NULL) // bound to rbegin()\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + (group_pointer->last_endpoint - group_pointer->elements) - 1;\r\n\t\t\t\t\t\telement_pointer = (group_pointer->last_endpoint - 1) - *skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer -= *skipfield_pointer;\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if ((distance -= group_pointer->size) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\t\t\t\t\t\telement_pointer = group_pointer->elements + *(group_pointer->skipfield);\r\n\t\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tgroup_pointer = group_pointer->next_group;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\t// Final group (if not already reached):\r\n\t\t\t\tif (group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max()) // No erasures in this group, use straight pointer addition\r\n\t\t\t\t{\r\n\t\t\t\t\telement_pointer = group_pointer->elements + distance;\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + distance;\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t\telse // ie. size > distance - safe to ignore endpoint check condition while incrementing:\r\n\t\t\t\t{\r\n\t\t\t\t\tskipfield_pointer = group_pointer->skipfield + *(group_pointer->skipfield);\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++skipfield_pointer;\r\n\t\t\t\t\t\tskipfield_pointer += *skipfield_pointer;\r\n\t\t\t\t\t} while(--distance != 0);\r\n\r\n\t\t\t\t\telement_pointer = group_pointer->elements + (skipfield_pointer - group_pointer->skipfield);\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\r\n\tpublic:\r\n\r\n\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t// move constructors\r\n\t\t\tcolony_reverse_iterator (colony_reverse_iterator &&source) PLF_NOEXCEPT:\r\n\t\t\t\tit(std::move(source.it))\r\n\t\t\t{}\r\n\r\n\t\t\tcolony_reverse_iterator (colony_reverse_iterator<!r_is_const> &&source) PLF_NOEXCEPT:\r\n\t\t\t\tit(std::move(source.it))\r\n\t\t\t{}\r\n\t\t#endif\r\n\r\n\t}; // colony_reverse_iterator\r\n\r\n\r\n\r\n\r\nprivate:\r\n\r\n\t// Used to prevent fill-insert/constructor calls being mistakenly resolved to range-insert/constructor calls\r\n\r\n\ttemplate <bool condition, class T = void>\r\n\tstruct plf_enable_if_c\r\n\t{\r\n\t\ttypedef T type;\r\n\t};\r\n\r\n\ttemplate <class T>\r\n\tstruct plf_enable_if_c<false, T>\r\n\t{};\r\n\r\n\r\n\r\n\t// Colony Member variables:\r\n\r\n\titerator\t\t\t\t\tend_iterator, begin_iterator;\r\n\tgroup_pointer_type\tgroups_with_erasures_list_head,\t// Head of the singly-linked list of groups which have erased-element memory locations available for re-use\r\n\t\t\t\t\t\t\t\tunused_groups_head;\t\t\t\t\t// Head of singly-linked list of groups retained by erase() or created by reserve()\r\n\tsize_type\t\t\t\ttotal_size, total_capacity;\r\n\r\n\tstruct ebco_pair2 : tuple_allocator_type // Packaging the element pointer allocator with a lesser-used member variable, for empty-base-class optimisation\r\n\t{\r\n\t\tskipfield_type min_group_capacity;\r\n\t\texplicit ebco_pair2(const skipfield_type min_elements) PLF_NOEXCEPT: min_group_capacity(min_elements) {}\r\n\t}\t\t\t\t\t\t\ttuple_allocator_pair;\r\n\r\n\tstruct ebco_pair : group_allocator_type\r\n\t{\r\n\t\tskipfield_type max_group_capacity;\r\n\t\texplicit ebco_pair(const skipfield_type max_elements) PLF_NOEXCEPT: max_group_capacity(max_elements) {}\r\n\t}\t\t\t\t\t\t\tgroup_allocator_pair;\r\n\r\n\r\n\r\n\t// An adaptive minimum based around sizeof(element_type), sizeof(group) and sizeof(colony):\r\n\t#define PLF_MIN_BLOCK_CAPACITY (sizeof(aligned_element_type) * 8 > (sizeof(plf::colony<element_type>) + sizeof(group)) * 2) ? 8 : (((sizeof(plf::colony<element_type>) + sizeof(group)) * 2) / sizeof(aligned_element_type))\r\n\r\n\r\n\r\n\tinline void check_capacities_conformance(plf::colony_limits capacities) const\r\n\t{\r\n  \t\tif (capacities.min < 2 || capacities.min > capacities.max || capacities.max > std::numeric_limits<skipfield_type>::max())\r\n\t\t{\r\n\t\t\tthrow std::length_error(\"Supplied memory block capacities outside of allowable ranges\");\r\n\t\t}\r\n\t}\r\n\r\n\r\n\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\tinline void check_skipfield_conformance() const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tPLF_STATIC_ASSERT(sizeof(element_type) >= sizeof(skipfield_type) * 2, \"Element type is not large enough to accomodate colony requirements under C++98/03. Change to C++11 or above, or use a larger type.\"); // eg. under C++98/03, aligned_storage is not available, so sizeof(skipfield type) * 2 must be larger or equal to sizeof(element_type), otherwise the doubly-linked free lists of erased element indexes will not work correctly. So if you're storing chars, for example, and the skipfield type is unsigned short (currently default for this implementation), the compiler will flag you with this assert. Which means you cannot store char or unsigned char in colony under C++03, and if storing short or unsigned short you must use the priority::memory_use parameter in your template instantiation. Or just use C++11 and above.\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\npublic:\r\n\r\n\t// Default constructor:\r\n\r\n\tcolony():\r\n\t\tallocator_type(allocator_type()),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(PLF_MIN_BLOCK_CAPACITY),\r\n\t\tgroup_allocator_pair(std::numeric_limits<skipfield_type>::max())\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t}\r\n\r\n\r\n\r\n\texplicit colony(const plf::colony_limits capacities):\r\n\t\tallocator_type(allocator_type()),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t}\r\n\r\n\r\n\r\n\t// Default constructor (allocator-extended):\r\n\r\n\texplicit colony(const allocator_type &alloc):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(PLF_MIN_BLOCK_CAPACITY),\r\n\t\tgroup_allocator_pair(std::numeric_limits<skipfield_type>::max())\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t}\r\n\r\n\r\n\r\n\texplicit colony(const plf::colony_limits capacities, const allocator_type &alloc):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t}\r\n\r\n\r\n\r\n\t// Copy constructor:\r\n\r\n\tcolony(const colony &source):\r\n\t\tallocator_type(source),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>((source.tuple_allocator_pair.min_group_capacity > source.total_size) ? source.tuple_allocator_pair.min_group_capacity : ((source.total_size > source.group_allocator_pair.max_group_capacity) ? source.group_allocator_pair.max_group_capacity : source.total_size))), // min group size is set to value closest to total number of elements in source colony in order to not create unnecessary small groups in the range-insert below, then reverts to the original min group size afterwards. This effectively saves a call to reserve.\r\n\t\tgroup_allocator_pair(source.group_allocator_pair.max_group_capacity)\r\n\t{ // can skip checking for skipfield conformance here as the skipfields must be equal between the destination and source, and source will have already had theirs checked. Same applies for other copy and move constructors below\r\n\t\trange_assign(source.begin_iterator, source.total_size);\r\n\t\ttuple_allocator_pair.min_group_capacity = source.tuple_allocator_pair.min_group_capacity; // reset to correct value for future clear() or erasures\r\n\t}\r\n\r\n\r\n\r\n\t// Copy constructor (allocator-extended):\r\n\r\n\tcolony(const colony &source, const allocator_type &alloc):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>((source.tuple_allocator_pair.min_group_capacity > source.total_size) ? source.tuple_allocator_pair.min_group_capacity : ((source.total_size > source.group_allocator_pair.max_group_capacity) ? source.group_allocator_pair.max_group_capacity : source.total_size))),\r\n\t\tgroup_allocator_pair(source.group_allocator_pair.max_group_capacity)\r\n\t{\r\n\t\trange_assign(source.begin_iterator, source.total_size);\r\n\t\ttuple_allocator_pair.min_group_capacity = source.tuple_allocator_pair.min_group_capacity;\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\tinline void blank() PLF_NOEXCEPT\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_trivial<group_pointer_type>::value && std::is_trivial<aligned_pointer_type>::value && std::is_trivial<skipfield_pointer_type>::value)\t// if all pointer types are trivial, we can just nuke it from orbit with memset (NULL is always 0 in C++):\r\n\t\t\t{\r\n\t\t\t\tstd::memset(static_cast<void *>(this), 0, offsetof(colony, tuple_allocator_pair));\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tend_iterator.group_pointer = NULL;\r\n\t\t\tend_iterator.element_pointer = NULL;\r\n\t\t\tend_iterator.skipfield_pointer = NULL;\r\n\t\t\tbegin_iterator.group_pointer = NULL;\r\n\t\t\tbegin_iterator.element_pointer = NULL;\r\n\t\t\tbegin_iterator.skipfield_pointer = NULL;\r\n\t\t\tgroups_with_erasures_list_head = NULL;\r\n\t\t\tunused_groups_head = NULL;\r\n\t\t\ttotal_size = 0;\r\n\t\t\ttotal_capacity = 0;\r\n\t\t}\r\n\t}\r\n\r\npublic:\r\n\r\n\r\n\r\n\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t// Move constructor:\r\n\r\n\t\tcolony(colony &&source) PLF_NOEXCEPT:\r\n\t\t\tallocator_type(source),\r\n\t\t\tend_iterator(std::move(source.end_iterator)),\r\n\t\t\tbegin_iterator(std::move(source.begin_iterator)),\r\n\t\t\tgroups_with_erasures_list_head(std::move(source.groups_with_erasures_list_head)),\r\n\t\t\tunused_groups_head(std::move(source.unused_groups_head)),\r\n\t\t\ttotal_size(source.total_size),\r\n\t\t\ttotal_capacity(source.total_capacity),\r\n\t\t\ttuple_allocator_pair(source.tuple_allocator_pair.min_group_capacity),\r\n\t\t\tgroup_allocator_pair(source.group_allocator_pair.max_group_capacity)\r\n\t\t{\r\n\t\t\tassert(&source != this);\r\n\t\t\tsource.blank();\r\n\t\t}\r\n\r\n\r\n\r\n\t\t// Move constructor (allocator-extended):\r\n\r\n\t\tcolony(colony &&source, const allocator_type &alloc):\r\n\t\t\tallocator_type(alloc),\r\n\t\t\tend_iterator(std::move(source.end_iterator)),\r\n\t\t\tbegin_iterator(std::move(source.begin_iterator)),\r\n\t\t\tgroups_with_erasures_list_head(std::move(source.groups_with_erasures_list_head)),\r\n\t\t\tunused_groups_head(std::move(source.unused_groups_head)),\r\n\t\t\ttotal_size(source.total_size),\r\n\t\t\ttotal_capacity(source.total_capacity),\r\n\t\t\ttuple_allocator_pair(source.tuple_allocator_pair.min_group_capacity),\r\n\t\t\tgroup_allocator_pair(source.group_allocator_pair.max_group_capacity)\r\n\t\t{\r\n\t\t\tassert(&source != this);\r\n\t\t\tsource.blank();\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t// Fill constructor:\r\n\r\n\tcolony(const size_type fill_number, const element_type &element, const plf::colony_limits capacities = plf::colony_limits(PLF_MIN_BLOCK_CAPACITY, std::numeric_limits<skipfield_type>::max()), const allocator_type &alloc = allocator_type()):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t\tassign(fill_number, element);\r\n\t}\r\n\r\n\r\n\r\n\t// Default-value fill constructor:\r\n\r\n\texplicit colony(const size_type fill_number, const plf::colony_limits capacities = plf::colony_limits(PLF_MIN_BLOCK_CAPACITY, std::numeric_limits<skipfield_type>::max()), const allocator_type &alloc = allocator_type()):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t\tassign(fill_number, element_type());\r\n\t}\r\n\r\n\r\n\r\n\t// Range constructor:\r\n\r\n\ttemplate<typename iterator_type>\r\n\tcolony(const typename plf_enable_if_c<!std::numeric_limits<iterator_type>::is_integer, iterator_type>::type &first, const iterator_type &last, const plf::colony_limits capacities = plf::colony_limits(PLF_MIN_BLOCK_CAPACITY, std::numeric_limits<skipfield_type>::max()), const allocator_type &alloc = allocator_type()):\r\n\t\tallocator_type(alloc),\r\n\t\tgroups_with_erasures_list_head(NULL),\r\n\t\tunused_groups_head(NULL),\r\n\t\ttotal_size(0),\r\n\t\ttotal_capacity(0),\r\n\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t{\r\n\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\tcheck_skipfield_conformance();\r\n\t\t#endif\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t\tassign<iterator_type>(first, last);\r\n\t}\r\n\r\n\r\n\r\n\t// Initializer-list constructor:\r\n\r\n\t#ifdef PLF_INITIALIZER_LIST_SUPPORT\r\n\t\tcolony(const std::initializer_list<element_type> &element_list, const plf::colony_limits capacities = plf::colony_limits(PLF_MIN_BLOCK_CAPACITY, std::numeric_limits<skipfield_type>::max()), const allocator_type &alloc = allocator_type()):\r\n\t\t\tallocator_type(alloc),\r\n\t\t\tgroups_with_erasures_list_head(NULL),\r\n\t\t\tunused_groups_head(NULL),\r\n\t\t\ttotal_size(0),\r\n\t\t\ttotal_capacity(0),\r\n\t\t\ttuple_allocator_pair(static_cast<skipfield_type>(capacities.min)),\r\n\t\t\tgroup_allocator_pair(static_cast<skipfield_type>(capacities.max))\r\n\t\t{\r\n\t\t\t#ifndef PLF_ALIGNMENT_SUPPORT\r\n\t\t\t\tcheck_skipfield_conformance();\r\n\t\t\t#endif\r\n\t\t\tcheck_capacities_conformance(capacities);\r\n\t\t\trange_assign(element_list.begin(), static_cast<size_type>(element_list.size()));\r\n\t\t}\r\n\r\n\t#endif\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE iterator begin() PLF_NOEXCEPT\r\n\t{\r\n\t\treturn begin_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE const_iterator begin() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn begin_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE iterator end() PLF_NOEXCEPT\r\n\t{\r\n\t\treturn end_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE const_iterator end() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn end_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE const_iterator cbegin() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn begin_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE const_iterator cend() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn end_iterator;\r\n\t}\r\n\r\n\r\n\r\n\tinline reverse_iterator rbegin() PLF_NOEXCEPT\r\n\t{\r\n\t\treturn (end_iterator.group_pointer != NULL) ? ++reverse_iterator(end_iterator) : reverse_iterator(begin_iterator.group_pointer, begin_iterator.element_pointer - 1, begin_iterator.skipfield_pointer - 1);\r\n\t}\r\n\r\n\r\n\r\n\tinline reverse_iterator rend() PLF_NOEXCEPT\r\n\t{\r\n\t\treturn reverse_iterator(begin_iterator.group_pointer, begin_iterator.element_pointer - 1, begin_iterator.skipfield_pointer - 1);\r\n\t}\r\n\r\n\r\n\r\n\tinline const_reverse_iterator crbegin() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn (end_iterator.group_pointer != NULL) ? ++const_reverse_iterator(end_iterator) : const_reverse_iterator(begin_iterator.group_pointer, begin_iterator.element_pointer - 1, begin_iterator.skipfield_pointer - 1);\r\n\t}\r\n\r\n\r\n\r\n\tinline const_reverse_iterator crend() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn const_reverse_iterator(begin_iterator.group_pointer, begin_iterator.element_pointer - 1, begin_iterator.skipfield_pointer - 1);\r\n\t}\r\n\r\n\r\n\r\n\t~colony() PLF_NOEXCEPT\r\n\t{\r\n\t\tdestroy_all_data();\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\r\n\tgroup_pointer_type allocate_new_group(const skipfield_type elements_per_group, group_pointer_type const previous = NULL)\r\n\t{\r\n\t\tgroup_pointer_type const new_group = PLF_ALLOCATE(group_allocator_type, group_allocator_pair, 1, 0);\r\n\r\n\t\ttry\r\n\t\t{\r\n\t\t\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\t\t\tPLF_CONSTRUCT(group_allocator_type, group_allocator_pair, new_group, elements_per_group, previous);\r\n\t\t\t#else\r\n\t\t\t\tPLF_CONSTRUCT(group_allocator_type, group_allocator_pair, new_group, group(elements_per_group, previous));\r\n\t\t\t#endif\r\n\t\t}\r\n\t\tcatch (...)\r\n\t\t{\r\n\t\t\tPLF_DEALLOCATE(group_allocator_type, group_allocator_pair, new_group, 1);\r\n\t\t\tthrow;\r\n\t\t}\r\n\r\n\t\treturn new_group;\r\n\t}\r\n\r\n\r\n\r\n\tinline void deallocate_group(group_pointer_type const the_group) PLF_NOEXCEPT\r\n\t{\r\n\t\tPLF_DESTROY(group_allocator_type, group_allocator_pair, the_group);\r\n\t\tPLF_DEALLOCATE(group_allocator_type, group_allocator_pair, the_group, 1);\r\n\t}\r\n\r\n\r\n\r\n\tvoid destroy_all_data() PLF_NOEXCEPT\r\n\t{\r\n\t\tif (begin_iterator.group_pointer != NULL)\r\n\t\t{\r\n\t\t\tend_iterator.group_pointer->next_group = unused_groups_head;\r\n\r\n\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t#endif // If compiler doesn't support traits, iterate regardless - trivial destructors will not be called, hopefully compiler will optimise the 'destruct' loop out for POD types\r\n\t\t\t{\r\n\t\t\t\tif (total_size != 0)\r\n\t\t\t\t{\r\n\t\t\t\t\twhile (true) // Erase elements without bothering to update skipfield - much faster:\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst aligned_pointer_type end_pointer = begin_iterator.group_pointer->last_endpoint;\r\n\r\n\t\t\t\t\t\tdo\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(begin_iterator.element_pointer));\r\n\t\t\t\t\t\t\tbegin_iterator.element_pointer += static_cast<size_type>(*++begin_iterator.skipfield_pointer) + 1u;\r\n\t\t\t\t\t\t\tbegin_iterator.skipfield_pointer += *begin_iterator.skipfield_pointer;\r\n\t\t\t\t\t\t} while(begin_iterator.element_pointer != end_pointer); // ie. beyond end of available data\r\n\r\n\t\t\t\t\t\tconst group_pointer_type next_group = begin_iterator.group_pointer->next_group;\r\n\t\t\t\t\t\tdeallocate_group(begin_iterator.group_pointer);\r\n\t\t\t\t\t\tbegin_iterator.group_pointer = next_group;\r\n\r\n\t\t\t\t\t\tif (next_group == unused_groups_head)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tbegin_iterator.element_pointer = next_group->elements + *(next_group->skipfield);\r\n\t\t\t\t\t\tbegin_iterator.skipfield_pointer = next_group->skipfield + *(next_group->skipfield);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\twhile (begin_iterator.group_pointer != NULL)\r\n\t\t\t{\r\n\t\t\t\tconst group_pointer_type next_group = begin_iterator.group_pointer->next_group;\r\n\t\t\t\tdeallocate_group(begin_iterator.group_pointer);\r\n\t\t\t\tbegin_iterator.group_pointer = next_group;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\tvoid initialize(const skipfield_type first_group_size)\r\n\t{\r\n\t\tend_iterator.group_pointer = begin_iterator.group_pointer = allocate_new_group(first_group_size);\r\n\t\tend_iterator.element_pointer = begin_iterator.element_pointer = begin_iterator.group_pointer->elements;\r\n\t\tend_iterator.skipfield_pointer = begin_iterator.skipfield_pointer = begin_iterator.group_pointer->skipfield;\r\n\t\ttotal_capacity = first_group_size;\r\n\t}\r\n\r\n\r\n\r\n\tvoid update_skipblock(const iterator &new_location, const skipfield_type prev_free_list_index) PLF_NOEXCEPT\r\n\t{\r\n\t\tconst skipfield_type new_value = static_cast<skipfield_type>(*(new_location.skipfield_pointer) - 1);\r\n\r\n\t\tif (new_value != 0) // ie. skipfield was not 1, ie. a single-node skipblock, with no additional nodes to update\r\n\t\t{\r\n\t\t\t// set (new) start and (original) end of skipblock to new value:\r\n\t\t\t*(new_location.skipfield_pointer + new_value) = *(new_location.skipfield_pointer + 1) = new_value;\r\n\r\n\t\t\t// transfer free list node to new start node:\r\n\t\t\t++(groups_with_erasures_list_head->free_list_head);\r\n\r\n\t\t\tif (prev_free_list_index != std::numeric_limits<skipfield_type>::max()) // ie. not the tail free list node\r\n\t\t\t{\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(new_location.group_pointer->elements + prev_free_list_index) + 1) = groups_with_erasures_list_head->free_list_head;\r\n\t\t\t}\r\n\r\n\t\t\t*(reinterpret_cast<skipfield_pointer_type>(new_location.element_pointer + 1)) = prev_free_list_index;\r\n\t\t\t*(reinterpret_cast<skipfield_pointer_type>(new_location.element_pointer + 1) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tgroups_with_erasures_list_head->free_list_head = prev_free_list_index;\r\n\r\n\t\t\tif (prev_free_list_index != std::numeric_limits<skipfield_type>::max()) // ie. not the last free list node\r\n\t\t\t{\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(new_location.group_pointer->elements + prev_free_list_index) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t}\r\n\t\t\telse // remove this group from the list of groups with erasures\r\n\t\t\t{\r\n\t\t\t\tgroups_with_erasures_list_head = groups_with_erasures_list_head->erasures_list_next_group;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t*(new_location.skipfield_pointer) = 0;\r\n\t\t++(new_location.group_pointer->size);\r\n\r\n\t\tif (new_location.group_pointer == begin_iterator.group_pointer && new_location.element_pointer < begin_iterator.element_pointer)\r\n\t\t{ /* ie. begin_iterator was moved forwards as the result of an erasure at some point, this erased element is before the current begin, hence, set current begin iterator to this element */\r\n\t\t\tbegin_iterator = new_location;\r\n\t\t}\r\n\r\n\t\t++total_size;\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\r\n\titerator insert(const element_type &element)\r\n\t{\r\n\t\tif (end_iterator.element_pointer != NULL)\r\n\t\t{\r\n\t\t\tif (groups_with_erasures_list_head == NULL) // ie. there are no erased elements and end_iterator is not at end of current final group\r\n\t\t\t{\r\n\t\t\t\tif (end_iterator.element_pointer != reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield))\r\n\t\t\t\t{\r\n\t\t\t\t\tconst iterator return_iterator = end_iterator; /* Make copy for return before modifying end_iterator */\r\n\r\n\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t\t\t\t{ // For no good reason this compiles to ridiculously faster code under GCC 5-9 in raw small struct tests with large N:\r\n\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), element);\r\n\t\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), element);\r\n\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = ++end_iterator.element_pointer; // Shift the addition to the second operation, avoiding a try-catch block if an exception is thrown during construction\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t++(end_iterator.group_pointer->size);\r\n\t\t\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\t\t\t++total_size;\r\n\r\n\t\t\t\t\treturn return_iterator; // return value before incrementation\r\n\t\t\t\t}\r\n\r\n\t\t\t\tgroup_pointer_type next_group;\r\n\r\n\t\t\t\tif (unused_groups_head == NULL)\r\n\t\t\t\t{\r\n\t\t\t\t\tconst skipfield_type new_group_size = (total_size < static_cast<size_type>(group_allocator_pair.max_group_capacity)) ? static_cast<skipfield_type>(total_size) : group_allocator_pair.max_group_capacity;\r\n\t\t\t\t\tnext_group = allocate_new_group(new_group_size, end_iterator.group_pointer);\r\n\r\n\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), element);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ttry\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), element);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tcatch (...)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tdeallocate_group(next_group);\r\n\t\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\ttotal_capacity += new_group_size;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tnext_group = unused_groups_head;\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), element);\r\n\t\t\t\t\tunused_groups_head = next_group->next_group;\r\n\t\t\t\t\tnext_group->reset(1, NULL, end_iterator.group_pointer, end_iterator.group_pointer->group_number + 1u);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tend_iterator.group_pointer->next_group = next_group;\r\n\t\t\t\tend_iterator.group_pointer = next_group;\r\n\t\t\t\tend_iterator.element_pointer = next_group->last_endpoint;\r\n\t\t\t\tend_iterator.skipfield_pointer = next_group->skipfield + 1;\r\n\t\t\t\t++total_size;\r\n\r\n\t\t\t\treturn iterator(next_group, next_group->elements, next_group->skipfield); /* returns value before incrementation */\r\n\t\t\t}\r\n\t\t\telse // ie. there are erased elements, reuse previous-erased element locations\r\n\t\t\t{\r\n\t\t\t\titerator new_location(groups_with_erasures_list_head, groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head, groups_with_erasures_list_head->skipfield + groups_with_erasures_list_head->free_list_head);\r\n\r\n\t\t\t\t// We always reuse the element at the start of the skipblock, this is also where the free-list information for that skipblock is stored. Get the previous free-list node's index from this memory space, before we write to our element to it. 'Next' index is always the free_list_head (as represented by the maximum value of the skipfield type) here so we don't need to get it:\r\n\t\t\t\tconst skipfield_type prev_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(new_location.element_pointer));\r\n\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(new_location.element_pointer), element);\r\n\t\t\t\tupdate_skipblock(new_location, prev_free_list_index);\r\n\r\n\t\t\t\treturn new_location;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse // ie. newly-constructed colony, no insertions yet and no groups\r\n\t\t{\r\n\t\t\tinitialize(tuple_allocator_pair.min_group_capacity);\r\n\r\n\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), element);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t#endif\r\n\t\t\t{\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), element);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (...)\r\n\t\t\t\t{\r\n\t\t\t\t\tclear();\r\n\t\t\t\t\tthrow;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\ttotal_size = 1;\r\n\t\t\treturn begin_iterator;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\titerator insert(element_type &&element) // The move-insert function is near-identical to the regular insert function, with the exception of the element construction method and is_nothrow tests.\r\n\t\t{\r\n\t\t\tif (end_iterator.element_pointer != NULL)\r\n\t\t\t{\r\n\t\t\t\tif (groups_with_erasures_list_head == NULL)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (end_iterator.element_pointer != reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst iterator return_iterator = end_iterator;\r\n\r\n\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_move_constructible<element_type>::value)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::move(element));\r\n\t\t\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), std::move(element));\r\n\t\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = ++end_iterator.element_pointer;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t++(end_iterator.group_pointer->size);\r\n\t\t\t\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\t\t\t\t++total_size;\r\n\r\n\t\t\t\t\t\treturn return_iterator;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tgroup_pointer_type next_group;\r\n\r\n\t\t\t\t\tif (unused_groups_head == NULL)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_type new_group_size = (total_size < static_cast<size_type>(group_allocator_pair.max_group_capacity)) ? static_cast<skipfield_type>(total_size) : group_allocator_pair.max_group_capacity;\r\n\t\t\t\t\t\tnext_group = allocate_new_group(new_group_size, end_iterator.group_pointer);\r\n\r\n\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_move_constructible<element_type>::value)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::move(element));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\ttry\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::move(element));\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tcatch (...)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tdeallocate_group(next_group);\r\n\t\t\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\ttotal_capacity += new_group_size;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tnext_group = unused_groups_head;\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::move(element));\r\n\t\t\t\t\t\tunused_groups_head = next_group->next_group;\r\n\t\t\t\t\t\tnext_group->reset(1, NULL, end_iterator.group_pointer, end_iterator.group_pointer->group_number + 1u);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tend_iterator.group_pointer->next_group = next_group;\r\n\t\t\t\t\tend_iterator.group_pointer = next_group;\r\n\t\t\t\t\tend_iterator.element_pointer = next_group->last_endpoint;\r\n\t\t\t\t\tend_iterator.skipfield_pointer = next_group->skipfield + 1;\r\n\t\t\t\t\t++total_size;\r\n\r\n\t\t\t\t\treturn iterator(next_group, next_group->elements, next_group->skipfield); /* returns value before incrementation */\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\titerator new_location(groups_with_erasures_list_head, groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head, groups_with_erasures_list_head->skipfield + groups_with_erasures_list_head->free_list_head);\r\n\r\n\t\t\t\t\tconst skipfield_type prev_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(new_location.element_pointer));\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(new_location.element_pointer), std::move(element));\r\n\t\t\t\t\tupdate_skipblock(new_location, prev_free_list_index);\r\n\r\n\t\t\t\t\treturn new_location;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tinitialize(tuple_allocator_pair.min_group_capacity);\r\n\r\n\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_move_constructible<element_type>::value)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::move(element));\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t#endif\r\n\t\t\t\t{\r\n\t\t\t\t\ttry\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::move(element));\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcatch (...)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tclear();\r\n\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\t\ttotal_size = 1;\r\n\t\t\t\treturn begin_iterator;\r\n\t\t\t}\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\ttemplate<typename... arguments>\r\n\t\titerator emplace(arguments &&... parameters) // The emplace function is near-identical to the regular insert function, with the exception of the element construction method, and change to is_nothrow tests.\r\n\t\t{\r\n\t\t\tif (end_iterator.element_pointer != NULL)\r\n\t\t\t{\r\n\t\t\t\tif (groups_with_erasures_list_head == NULL)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (end_iterator.element_pointer != reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst iterator return_iterator = end_iterator;\r\n\r\n\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_constructible<element_type>::value)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t\t\tend_iterator.group_pointer->last_endpoint = ++end_iterator.element_pointer;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t++(end_iterator.group_pointer->size);\r\n\t\t\t\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\t\t\t\t++total_size;\r\n\r\n\t\t\t\t\t\treturn return_iterator;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tgroup_pointer_type next_group;\r\n\r\n\t\t\t\t\tif (unused_groups_head == NULL)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_type new_group_size = (total_size < static_cast<size_type>(group_allocator_pair.max_group_capacity)) ? static_cast<skipfield_type>(total_size) : group_allocator_pair.max_group_capacity;\r\n\t\t\t\t\t\tnext_group = allocate_new_group(new_group_size, end_iterator.group_pointer);\r\n\r\n\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_constructible<element_type>::value)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\ttry\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tcatch (...)\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tdeallocate_group(next_group);\r\n\t\t\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\ttotal_capacity += new_group_size;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tnext_group = unused_groups_head;\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(next_group->elements), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t\tunused_groups_head = next_group->next_group;\r\n\t\t\t\t\t\tnext_group->reset(1, NULL, end_iterator.group_pointer, end_iterator.group_pointer->group_number + 1u);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tend_iterator.group_pointer->next_group = next_group;\r\n\t\t\t\t\tend_iterator.group_pointer = next_group;\r\n\t\t\t\t\tend_iterator.element_pointer = next_group->last_endpoint;\r\n\t\t\t\t\tend_iterator.skipfield_pointer = next_group->skipfield + 1;\r\n\t\t\t\t\t++total_size;\r\n\r\n\t\t\t\t\treturn iterator(next_group, next_group->elements, next_group->skipfield); /* returns value before incrementation */\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\titerator new_location(groups_with_erasures_list_head, groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head, groups_with_erasures_list_head->skipfield + groups_with_erasures_list_head->free_list_head);\r\n\r\n\t\t\t\t\tconst skipfield_type prev_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(new_location.element_pointer));\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(new_location.element_pointer), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\tupdate_skipblock(new_location, prev_free_list_index);\r\n\r\n\t\t\t\t\treturn new_location;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tinitialize(tuple_allocator_pair.min_group_capacity);\r\n\r\n\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\tif PLF_CONSTEXPR (std::is_nothrow_constructible<element_type, arguments ...>::value)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t#endif\r\n\t\t\t\t{\r\n\t\t\t\t\ttry\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer++), std::forward<arguments>(parameters) ...);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tcatch (...)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tclear();\r\n\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t++end_iterator.skipfield_pointer;\r\n\t\t\t\ttotal_size = 1;\r\n\t\t\t\treturn begin_iterator;\r\n\t\t\t}\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\r\nprivate:\r\n\r\n\t// For catch blocks in fill() and range_fill()\r\n\tvoid recover_from_partial_fill()\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT // try to ensure this code will not be generated if this function is not called in fill() or range_fill()\r\n\t\t\tif PLF_CONSTEXPR (!std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\tconst skipfield_type elements_constructed_before_exception = static_cast<skipfield_type>(end_iterator.element_pointer - end_iterator.group_pointer->elements);\r\n\t\t\tend_iterator.group_pointer->size = elements_constructed_before_exception;\r\n\t\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + elements_constructed_before_exception;\r\n\t\t\ttotal_size += elements_constructed_before_exception;\r\n\t\t\tunused_groups_head = end_iterator.group_pointer->next_group;\r\n\t\t\tend_iterator.group_pointer->next_group = NULL;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\tvoid fill(const element_type &element, const skipfield_type size)\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t{\r\n\t\t\t\tif PLF_CONSTEXPR (std::is_trivially_copyable<element_type>::value && std::is_trivially_copy_constructible<element_type>::value) // ie. we can get away with using the cheaper fill_n here if there is no chance of an exception being thrown:\r\n\t\t\t\t{\r\n\t\t\t\t\t#ifdef PLF_ALIGNMENT_SUPPORT\r\n\t\t\t\t\t\tif PLF_CONSTEXPR (sizeof(aligned_element_type) != sizeof(element_type))\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\talignas (alignof(aligned_element_type)) element_type aligned_copy = element; // to avoid potentially violating memory boundaries in line below, create an initial copy object of same (but aligned) type\r\n\t\t\t\t\t\t\tstd::fill_n(end_iterator.element_pointer, size, *(reinterpret_cast<aligned_pointer_type>(&aligned_copy)));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstd::fill_n(reinterpret_cast<pointer>(end_iterator.element_pointer), size, element);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tend_iterator.element_pointer += size;\r\n\t\t\t\t}\r\n\t\t\t\telse // If at least nothrow_constructible, can remove the large block of 'catch' code below\r\n\t\t\t\t{\r\n\t\t\t\t\tconst aligned_pointer_type fill_end = end_iterator.element_pointer + size;\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), element);\r\n\t\t\t\t\t} while (++end_iterator.element_pointer != fill_end);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tconst aligned_pointer_type fill_end = end_iterator.element_pointer + size;\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), element);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (...)\r\n\t\t\t\t{\r\n\t\t\t\t\trecover_from_partial_fill();\r\n\t\t\t\t\tthrow;\r\n\t\t\t\t}\r\n\t\t\t} while (++end_iterator.element_pointer != fill_end);\r\n\t\t}\r\n\r\n\t\ttotal_size += size;\r\n\t}\r\n\r\n\r\n\r\n\t// For catch blocks in range_fill_skipblock and fill_skipblock\r\n\tvoid recover_from_partial_skipblock_fill(aligned_pointer_type const location, const aligned_pointer_type current_location, skipfield_pointer_type const skipfield_pointer, const skipfield_type prev_free_list_node)\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT // try to ensure this code will not be generated if this function is not called in fill_skipblock or range_fill_skipblock\r\n\t\t\tif PLF_CONSTEXPR (!std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t#endif\r\n\t\t{\r\n\t\t\t// Reconstruct existing skipblock and free-list indexes to reflect partially-reused skipblock:\r\n\t\t\tconst skipfield_type elements_constructed_before_exception = static_cast<skipfield_type>((current_location - 1) - location);\r\n\t\t\tgroups_with_erasures_list_head->size = static_cast<skipfield_type>(groups_with_erasures_list_head->size + elements_constructed_before_exception);\r\n\t\t\ttotal_size += elements_constructed_before_exception;\r\n\r\n\t\t\tstd::memset(skipfield_pointer, 0, elements_constructed_before_exception * sizeof(skipfield_type));\r\n\r\n\t\t\t*(reinterpret_cast<skipfield_pointer_type>(location + elements_constructed_before_exception)) = prev_free_list_node;\r\n\t\t\t*(reinterpret_cast<skipfield_pointer_type>(location + elements_constructed_before_exception) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\r\n\t\t\tconst skipfield_type new_skipblock_head_index = static_cast<skipfield_type>((location - groups_with_erasures_list_head->elements) + elements_constructed_before_exception);\r\n\t\t\tgroups_with_erasures_list_head->free_list_head = new_skipblock_head_index;\r\n\r\n\t\t\tif (prev_free_list_node != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t{\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(groups_with_erasures_list_head->elements + prev_free_list_node) + 1) = new_skipblock_head_index;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\tvoid fill_skipblock(const element_type &element, aligned_pointer_type const location, skipfield_pointer_type const skipfield_pointer, const skipfield_type size)\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t{\r\n\t\t\t\tif PLF_CONSTEXPR (std::is_trivially_copyable<element_type>::value && std::is_trivially_copy_constructible<element_type>::value)\r\n\t\t\t\t{\r\n\t\t\t\t\t#ifdef PLF_ALIGNMENT_SUPPORT\r\n\t\t\t\t\t\tif PLF_CONSTEXPR (sizeof(aligned_element_type) != sizeof(element_type))\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\talignas (alignof(aligned_element_type)) element_type aligned_copy = element;\r\n\t\t\t\t\t\t\tstd::fill_n(location, size, *(reinterpret_cast<aligned_pointer_type>(&aligned_copy)));\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t#endif\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tstd::fill_n(reinterpret_cast<pointer>(location), size, element);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tconst aligned_pointer_type fill_end = location + size;\r\n\r\n\t\t\t\t\tfor (aligned_pointer_type current_location = location; current_location != fill_end; ++current_location)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(current_location), element);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tconst aligned_pointer_type fill_end = location + size;\r\n\t\t\tconst skipfield_type prev_free_list_node = *(reinterpret_cast<skipfield_pointer_type>(location)); // in case of exception, grabbing indexes before free_list node is reused\r\n\r\n\t\t\tfor (aligned_pointer_type current_location = location; current_location != fill_end; ++current_location)\r\n\t\t\t{\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(current_location), element);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (...)\r\n\t\t\t\t{\r\n\t\t\t\t\trecover_from_partial_skipblock_fill(location, current_location, skipfield_pointer, prev_free_list_node);\r\n\t\t\t\t\tthrow;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstd::memset(skipfield_pointer, 0, size * sizeof(skipfield_type)); // reset skipfield nodes within skipblock to 0\r\n\t\tgroups_with_erasures_list_head->size = static_cast<skipfield_type>(groups_with_erasures_list_head->size + size);\r\n\t\ttotal_size += size;\r\n\t}\r\n\r\n\r\n\r\n\tvoid fill_unused_groups(size_type size, const element_type &element, size_type group_number, group_pointer_type previous_group, const group_pointer_type current_group)\r\n\t{\r\n\t\tend_iterator.group_pointer = current_group;\r\n\r\n\t\tfor (; end_iterator.group_pointer->capacity < size; end_iterator.group_pointer = end_iterator.group_pointer->next_group)\r\n\t\t{\r\n\t\t\tconst skipfield_type capacity = end_iterator.group_pointer->capacity;\r\n\t\t\tend_iterator.group_pointer->reset(capacity, end_iterator.group_pointer->next_group, previous_group, group_number++);\r\n\t\t\tprevious_group = end_iterator.group_pointer;\r\n\t\t\tsize -= static_cast<size_type>(capacity);\r\n\t\t\tend_iterator.element_pointer = end_iterator.group_pointer->elements;\r\n\t\t\tfill(element, capacity);\r\n\t\t}\r\n\r\n\t\t// Deal with final group (partial fill)\r\n\t\tunused_groups_head = end_iterator.group_pointer->next_group;\r\n\t\tend_iterator.group_pointer->reset(static_cast<skipfield_type>(size), NULL, previous_group, group_number);\r\n\t\tend_iterator.element_pointer = end_iterator.group_pointer->elements;\r\n\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + size;\r\n\t\tfill(element, static_cast<skipfield_type>(size));\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\t// Fill insert\r\n\r\n\tvoid insert(size_type size, const element_type &element)\r\n\t{\r\n\t\tif (size == 0)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if (size == 1)\r\n\t\t{\r\n\t\t\tinsert(element);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (total_size == 0)\r\n\t\t{\r\n\t\t\tassign(size, element);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\treserve(total_size + size);\r\n\r\n\t\t// Use up erased locations if available:\r\n\t\twhile(groups_with_erasures_list_head != NULL) // skipblock loop: breaks when colony is exhausted of reusable skipblocks, or returns if size == 0\r\n\t\t{\r\n\t\t\taligned_pointer_type const element_pointer = groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head;\r\n\t\t\tskipfield_pointer_type const skipfield_pointer = groups_with_erasures_list_head->skipfield + groups_with_erasures_list_head->free_list_head;\r\n\t\t\tconst skipfield_type skipblock_size = *skipfield_pointer;\r\n\r\n\t\t\tif (groups_with_erasures_list_head == begin_iterator.group_pointer && element_pointer < begin_iterator.element_pointer)\r\n\t\t\t{\r\n\t\t\t\tbegin_iterator.element_pointer = element_pointer;\r\n\t\t\t\tbegin_iterator.skipfield_pointer = skipfield_pointer;\r\n\t\t\t}\r\n\r\n\t\t\tif (skipblock_size <= size)\r\n\t\t\t{\r\n\t\t\t\tgroups_with_erasures_list_head->free_list_head = *(reinterpret_cast<skipfield_pointer_type>(element_pointer)); // set free list head to previous free list node\r\n\t\t\t\tfill_skipblock(element, element_pointer, skipfield_pointer, skipblock_size);\r\n\t\t\t\tsize -= skipblock_size;\r\n\r\n\t\t\t\tif (groups_with_erasures_list_head->free_list_head != std::numeric_limits<skipfield_type>::max()) // ie. there are more skipblocks to be filled in this group\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head) + 1) = std::numeric_limits<skipfield_type>::max(); // set 'next' index of new free list head to 'end' (numeric max)\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tgroups_with_erasures_list_head = groups_with_erasures_list_head->erasures_list_next_group; // change groups\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (size == 0)\r\n\t\t\t\t{\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse // skipblock is larger than remaining number of elements\r\n\t\t\t{\r\n\t\t\t\tconst skipfield_type prev_index = *(reinterpret_cast<skipfield_pointer_type>(element_pointer)); // save before element location is overwritten\r\n\t\t\t\tfill_skipblock(element, element_pointer, skipfield_pointer, static_cast<skipfield_type>(size));\r\n\t\t\t\tconst skipfield_type new_skipblock_size = static_cast<skipfield_type>(skipblock_size - size);\r\n\r\n\t\t\t\t// Update skipfield (earlier nodes already memset'd in fill_skipblock function):\r\n\t\t\t\t*(skipfield_pointer + size) = new_skipblock_size;\r\n\t\t\t\t*(skipfield_pointer + skipblock_size - 1) = new_skipblock_size;\r\n\t\t\t\tgroups_with_erasures_list_head->free_list_head = static_cast<skipfield_type>(groups_with_erasures_list_head->free_list_head + size); // set free list head to new start node\r\n\r\n\t\t\t\t// Update free list with new head:\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(element_pointer + size)) = prev_index;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(element_pointer + size) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\r\n\t\t\t\tif (prev_index != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(groups_with_erasures_list_head->elements + prev_index) + 1) = groups_with_erasures_list_head->free_list_head; // set 'next' index of previous skipblock to new start of skipblock\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\t// Use up remaining available element locations in end group:\r\n\t\t// This variable is either the remaining capacity of the group or the number of elements yet to be filled, whichever is smaller:\r\n\t\tconst skipfield_type group_remainder = (static_cast<skipfield_type>(\r\n\t\t\treinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer) >= size) ?\r\n\t\t\tstatic_cast<skipfield_type>(size) :\r\n\t\t\tstatic_cast<skipfield_type>(reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer);\r\n\r\n\t\tif (group_remainder != 0)\r\n\t\t{\r\n\t\t\tfill(element, group_remainder);\r\n\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\tend_iterator.group_pointer->size = static_cast<skipfield_type>(end_iterator.group_pointer->size + group_remainder);\r\n\r\n\t\t\tif (size == group_remainder) // Ie. remaining capacity was >= remaining elements to be filled\r\n\t\t\t{\r\n\t\t\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + end_iterator.group_pointer->size;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tsize -= group_remainder;\r\n\t\t}\r\n\r\n\r\n\t\t// Use unused groups:\r\n\t\tend_iterator.group_pointer->next_group = unused_groups_head;\r\n\t\tfill_unused_groups(size, element, end_iterator.group_pointer->group_number + 1, end_iterator.group_pointer, unused_groups_head);\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\ttemplate <class iterator_type>\r\n\titerator_type range_fill(iterator_type it, const skipfield_type size)\r\n\t{\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t{\r\n\t\t\t\tconst aligned_pointer_type fill_end = end_iterator.element_pointer + size;\r\n\r\n\t\t\t\tdo\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), *it++);\r\n\t\t\t\t} while (++end_iterator.element_pointer != fill_end);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tconst aligned_pointer_type fill_end = end_iterator.element_pointer + size;\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(end_iterator.element_pointer), *it++);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (...)\r\n\t\t\t\t{\r\n\t\t\t\t\trecover_from_partial_fill();\r\n\t\t\t\t\tthrow;\r\n\t\t\t\t}\r\n\t\t\t} while (++end_iterator.element_pointer != fill_end);\r\n\t\t}\r\n\r\n\t\ttotal_size += size;\r\n\t\treturn it;\r\n\t}\r\n\r\n\r\n\r\n\ttemplate <class iterator_type>\r\n\titerator_type range_fill_skipblock(iterator_type it, aligned_pointer_type const location, skipfield_pointer_type const skipfield_pointer, const skipfield_type size)\r\n\t{\r\n\t\tconst aligned_pointer_type fill_end = location + size;\r\n\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_nothrow_copy_constructible<element_type>::value)\r\n\t\t\t{\r\n\t\t\t\tfor (aligned_pointer_type current_location = location; current_location != fill_end; ++current_location)\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(current_location), *it++);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tconst skipfield_type prev_free_list_node = *(reinterpret_cast<skipfield_pointer_type>(location)); // in case of exception, grabbing indexes before free_list node is reused\r\n\r\n\t\t\tfor (aligned_pointer_type current_location = location; current_location != fill_end; ++current_location)\r\n\t\t\t{\r\n\t\t\t\ttry\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_CONSTRUCT(allocator_type, *this, reinterpret_cast<pointer>(current_location), *it++);\r\n\t\t\t\t}\r\n\t\t\t\tcatch (...)\r\n\t\t\t\t{\r\n\t\t\t\t\trecover_from_partial_skipblock_fill(location, current_location, skipfield_pointer, prev_free_list_node);\r\n\t\t\t\t\tthrow;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tstd::memset(skipfield_pointer, 0, size * sizeof(skipfield_type)); // reset skipfield nodes within skipblock to 0\r\n\t\tgroups_with_erasures_list_head->size = static_cast<skipfield_type>(groups_with_erasures_list_head->size + size);\r\n\t\ttotal_size += size;\r\n\r\n\t\treturn it;\r\n\t}\r\n\r\n\r\n\r\n\ttemplate <class iterator_type>\r\n\tvoid range_fill_unused_groups(size_type size, iterator_type it, size_type group_number, group_pointer_type previous_group, const group_pointer_type current_group)\r\n\t{\r\n\t\tend_iterator.group_pointer = current_group;\r\n\r\n\t\tfor (; end_iterator.group_pointer->capacity < size; end_iterator.group_pointer = end_iterator.group_pointer->next_group)\r\n\t\t{\r\n\t\t\tconst skipfield_type capacity = end_iterator.group_pointer->capacity;\r\n\t\t\tend_iterator.group_pointer->reset(capacity, end_iterator.group_pointer->next_group, previous_group, group_number++);\r\n\t\t\tprevious_group = end_iterator.group_pointer;\r\n\t\t\tsize -= static_cast<size_type>(capacity);\r\n\t\t\tend_iterator.element_pointer = end_iterator.group_pointer->elements;\r\n\t\t\tit = range_fill(it, capacity);\r\n\t\t}\r\n\r\n\t\t// Deal with final group (partial fill)\r\n\t\tunused_groups_head = end_iterator.group_pointer->next_group;\r\n\t\tend_iterator.group_pointer->reset(static_cast<skipfield_type>(size), NULL, previous_group, group_number);\r\n\t\tend_iterator.element_pointer = end_iterator.group_pointer->elements;\r\n\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + size;\r\n\t\trange_fill(it, static_cast<skipfield_type>(size));\r\n\t}\r\n\r\n\r\n\r\n\ttemplate <class iterator_type>\r\n\tvoid range_insert (iterator_type it, size_type size) // this is near-identical to the fill insert, with the only alteration being incrementing an iterator for construction, rather than using a const element. And the fill etc function calls are changed to range_fill to match this pattern. comments have been removed, see fill insert for code explanations\r\n\t{\r\n\t\tif (size == 0)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if (size == 1)\r\n\t\t{\r\n\t\t\tinsert(*it);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (total_size == 0)\r\n\t\t{\r\n\t\t\trange_assign(it, size);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\r\n\t\treserve(total_size + size);\r\n\r\n\t\twhile(groups_with_erasures_list_head != NULL)\r\n\t\t{\r\n\t\t\taligned_pointer_type const element_pointer = groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head;\r\n\t\t\tskipfield_pointer_type const skipfield_pointer = groups_with_erasures_list_head->skipfield + groups_with_erasures_list_head->free_list_head;\r\n\t\t\tconst skipfield_type skipblock_size = *skipfield_pointer;\r\n\r\n\t\t\tif (groups_with_erasures_list_head == begin_iterator.group_pointer && element_pointer < begin_iterator.element_pointer)\r\n\t\t\t{\r\n\t\t\t\tbegin_iterator.element_pointer = element_pointer;\r\n\t\t\t\tbegin_iterator.skipfield_pointer = skipfield_pointer;\r\n\t\t\t}\r\n\r\n\t\t\tif (skipblock_size <= size)\r\n\t\t\t{\r\n\t\t\t\tgroups_with_erasures_list_head->free_list_head = *(reinterpret_cast<skipfield_pointer_type>(element_pointer));\r\n\t\t\t\tit = range_fill_skipblock(it, element_pointer, skipfield_pointer, skipblock_size);\r\n\t\t\t\tsize -= skipblock_size;\r\n\r\n\t\t\t\tif (groups_with_erasures_list_head->free_list_head != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(groups_with_erasures_list_head->elements + groups_with_erasures_list_head->free_list_head) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tgroups_with_erasures_list_head = groups_with_erasures_list_head->erasures_list_next_group;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (size == 0)\r\n\t\t\t\t{\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tconst skipfield_type prev_index = *(reinterpret_cast<skipfield_pointer_type>(element_pointer));\r\n\t\t\t\tit = range_fill_skipblock(it, element_pointer, skipfield_pointer, static_cast<skipfield_type>(size));\r\n\t\t\t\tconst skipfield_type new_skipblock_size = static_cast<skipfield_type>(skipblock_size - size);\r\n\r\n\t\t\t\t*(skipfield_pointer + size) = new_skipblock_size;\r\n\t\t\t\t*(skipfield_pointer + skipblock_size - 1) = new_skipblock_size;\r\n\t\t\t\tgroups_with_erasures_list_head->free_list_head = static_cast<skipfield_type>(groups_with_erasures_list_head->free_list_head + size);\r\n\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(element_pointer + size)) = prev_index;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(element_pointer + size) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\r\n\t\t\t\tif (prev_index != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(groups_with_erasures_list_head->elements + prev_index) + 1) = groups_with_erasures_list_head->free_list_head;\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tconst skipfield_type group_remainder = (static_cast<skipfield_type>(\r\n\t\t\treinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer) >= size) ?\r\n\t\t\tstatic_cast<skipfield_type>(size) :\r\n\t\t\tstatic_cast<skipfield_type>(reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer);\r\n\r\n\t\tif (group_remainder != 0)\r\n\t\t{\r\n\t\t\tit = range_fill(it, group_remainder);\r\n\t\t\tend_iterator.group_pointer->last_endpoint = end_iterator.element_pointer;\r\n\t\t\tend_iterator.group_pointer->size = static_cast<skipfield_type>(end_iterator.group_pointer->size + group_remainder);\r\n\r\n\t\t\tif (size == group_remainder)\r\n\t\t\t{\r\n\t\t\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + end_iterator.group_pointer->size;\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tsize -= group_remainder;\r\n\t\t}\r\n\r\n\r\n\t\tend_iterator.group_pointer->next_group = unused_groups_head;\r\n\t\trange_fill_unused_groups(size, it, end_iterator.group_pointer->group_number + 1, end_iterator.group_pointer, unused_groups_head);\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\t// Range insert:\r\n\r\n \ttemplate <class iterator_type>\r\n \tinline void insert (const typename plf_enable_if_c<!std::numeric_limits<iterator_type>::is_integer, iterator_type>::type first, const iterator_type last)\r\n \t{\r\n\t\tusing std::distance;\r\n \t\trange_insert(first, static_cast<size_type>(distance(first, last)));\r\n \t}\r\n\r\n\r\n\r\n\t// Range insert for differing iterator types eg. sentinels:\r\n\r\n\t#ifdef PLF_CPP20_SUPPORT\r\n\t\ttemplate <class iterator_type1, class iterator_type2>\r\n\t\t\trequires (!std::same_as<iterator_type1, iterator_type2> && std::equality_comparable_with<iterator_type1, iterator_type2> && !std::integral<iterator_type1> && !std::integral<iterator_type2>)\r\n\t\tinline void insert (const iterator_type1 first, const iterator_type2 last)\r\n\t\t{\r\n\t\t\tsize_type distance = 0;\r\n\t\t\tfor(iterator_type1 current = first; current != last; ++current, ++distance) {};\r\n\t\t\trange_insert(first, distance);\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t// Range insert, move_iterator overload:\r\n\r\n\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\ttemplate <class iterator_type>\r\n\t\tinline void insert (const std::move_iterator<iterator_type> first, const std::move_iterator<iterator_type> last)\r\n\t\t{\r\n\t\t\tusing std::distance;\r\n\t\t\trange_insert(first, static_cast<size_type>(distance(first.base(),last.base())));\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t// Initializer-list insert\r\n\r\n\t#ifdef PLF_INITIALIZER_LIST_SUPPORT\r\n\t\tinline void insert (const std::initializer_list<element_type> &element_list)\r\n\t\t{\r\n\t\t\trange_insert(element_list.begin(), static_cast<size_type>(element_list.size()));\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\nprivate:\r\n\r\n\tinline PLF_FORCE_INLINE void update_subsequent_group_numbers(group_pointer_type current_group) PLF_NOEXCEPT\r\n\t{\r\n\t\tdo\r\n\t\t{\r\n\t\t\t--(current_group->group_number);\r\n\t\t\tcurrent_group = current_group->next_group;\r\n\t\t} while (current_group != NULL);\r\n\t}\r\n\r\n\r\n\r\n\tvoid remove_from_groups_with_erasures_list(const group_pointer_type group_to_remove) PLF_NOEXCEPT\r\n\t{\r\n\t\tif (group_to_remove == groups_with_erasures_list_head)\r\n\t\t{\r\n\t\t\tgroups_with_erasures_list_head = groups_with_erasures_list_head->erasures_list_next_group;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tgroup_pointer_type previous_group = groups_with_erasures_list_head, current_group = groups_with_erasures_list_head->erasures_list_next_group;\r\n\r\n\t\twhile (group_to_remove != current_group)\r\n\t\t{\r\n\t\t\tprevious_group = current_group;\r\n\t\t\tcurrent_group = current_group->erasures_list_next_group;\r\n\t\t}\r\n\r\n\t\tprevious_group->erasures_list_next_group = current_group->erasures_list_next_group;\r\n\t}\r\n\r\n\r\n\r\n\tinline void reset_only_group_left(group_pointer_type const group_pointer) PLF_NOEXCEPT\r\n\t{\r\n\t\tgroups_with_erasures_list_head = NULL;\r\n\t\tgroup_pointer->reset(0, NULL, NULL, 0);\r\n\r\n\t\t// Reset begin and end iterators:\r\n\t\tend_iterator.element_pointer = begin_iterator.element_pointer = group_pointer->last_endpoint;\r\n\t\tend_iterator.skipfield_pointer = begin_iterator.skipfield_pointer = group_pointer->skipfield;\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE void add_group_to_unused_groups_list(group * const group_pointer) PLF_NOEXCEPT\r\n\t{\r\n\t\tgroup_pointer->next_group = unused_groups_head;\r\n\t\tunused_groups_head = group_pointer;\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\t// must return iterator to subsequent non-erased element (or end()), in case the group containing the element which the iterator points to becomes empty after the erasure, and is thereafter removed from the colony chain, making the current iterator invalid and unusable in a ++ operation:\r\n\titerator erase(const const_iterator it) // if uninitialized/invalid iterator supplied, function could generate an exception\r\n\t{\r\n\t\tassert(total_size != 0);\r\n\t\tassert(it.group_pointer != NULL); // ie. not uninitialized iterator\r\n\t\tassert(it.element_pointer != it.group_pointer->last_endpoint); // ie. != end()\r\n\t\tassert(*(it.skipfield_pointer) == 0); // ie. element pointed to by iterator has not been erased previously\r\n\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value) // This if-statement should be removed by the compiler on resolution of element_type. For some optimizing compilers this step won't be necessary (for MSVC 2013 it makes a difference)\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(it.element_pointer)); // Destruct element\r\n\t\t}\r\n\r\n\t\t--total_size;\r\n\r\n\t\tif (it.group_pointer->size-- != 1) // ie. non-empty group at this point in time, don't consolidate - optimization note: GCC optimizes postfix - 1 comparison better than prefix - 1 comparison in many cases.\r\n\t\t{\r\n\t\t\t// Code logic for following section:\r\n\t\t\t// ---------------------------------\r\n\t\t\t// If current skipfield node has no skipped node on either side, continue as usual\r\n\t\t\t// If node only has skipped node on left, set current node and start node of the skipblock to left node value + 1.\r\n\t\t\t// If node only has skipped node on right, make this node the start node of the skipblock and update end node\r\n\t\t\t// If node has skipped nodes on left and right, set start node of left skipblock and end node of right skipblock to the values of the left + right nodes + 1\r\n\r\n\t\t\t// Optimization explanation:\r\n\t\t\t// The contextual logic below is the same as that in the insert() functions but in this case the value of the current skipfield node will always be\r\n\t\t\t// zero (since it is not yet erased), meaning no additional manipulations are necessary for the previous skipfield node comparison - we only have to check against zero\r\n\t\t\tconst char prev_skipfield = *(it.skipfield_pointer - (it.skipfield_pointer != it.group_pointer->skipfield)) != 0;\r\n\t\t\tconst char after_skipfield = *(it.skipfield_pointer + 1) != 0;  // NOTE: boundary test (checking against end-of-elements) is able to be skipped due to the extra skipfield node (compared to element field) - which is present to enable faster iterator operator ++ operations\r\n\t\t\tskipfield_type update_value = 1;\r\n\r\n\t\t\tif (!(prev_skipfield | after_skipfield)) // no consecutive erased elements\r\n\t\t\t{\r\n\t\t\t\t*it.skipfield_pointer = 1; // solo skipped node\r\n\t\t\t\tconst skipfield_type index = static_cast<skipfield_type>(it.element_pointer - it.group_pointer->elements);\r\n\r\n\t\t\t\tif (it.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max()) // ie. if this group already has some erased elements\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.group_pointer->elements + it.group_pointer->free_list_head) + 1) = index; // set prev free list head's 'next index' number to the index of the current element\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tit.group_pointer->erasures_list_next_group = groups_with_erasures_list_head; // add it to the groups-with-erasures free list\r\n\t\t\t\t\tgroups_with_erasures_list_head = it.group_pointer;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.element_pointer)) = it.group_pointer->free_list_head;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.element_pointer) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\tit.group_pointer->free_list_head = index;\r\n\t\t\t}\r\n\t\t\telse if (prev_skipfield & (!after_skipfield)) // previous erased consecutive elements, none following\r\n\t\t\t{\r\n\t\t\t\t*(it.skipfield_pointer - *(it.skipfield_pointer - 1)) = *it.skipfield_pointer = static_cast<skipfield_type>(*(it.skipfield_pointer - 1) + 1);\r\n\t\t\t}\r\n\t\t\telse if ((!prev_skipfield) & after_skipfield) // following erased consecutive elements, none preceding\r\n\t\t\t{\r\n\t\t\t\tconst skipfield_type following_value = static_cast<skipfield_type>(*(it.skipfield_pointer + 1) + 1);\r\n\t\t\t\t*(it.skipfield_pointer + following_value - 1) = *(it.skipfield_pointer) = following_value;\r\n\r\n\t\t\t\tconst skipfield_type following_previous = *(reinterpret_cast<skipfield_pointer_type>(it.element_pointer + 1));\r\n\t\t\t\tconst skipfield_type following_next = *(reinterpret_cast<skipfield_pointer_type>(it.element_pointer + 1) + 1);\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.element_pointer)) = following_previous;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.element_pointer) + 1) = following_next;\r\n\r\n\t\t\t\tconst skipfield_type index = static_cast<skipfield_type>(it.element_pointer - it.group_pointer->elements);\r\n\r\n\t\t\t\tif (following_previous != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.group_pointer->elements + following_previous) + 1) = index; // Set next index of previous free list node to this node's 'next' index\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (following_next != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.group_pointer->elements + following_next)) = index;\t// Set previous index of next free list node to this node's 'previous' index\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tit.group_pointer->free_list_head = index;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tupdate_value = following_value;\r\n\t\t\t}\r\n\t\t\telse // both preceding and following consecutive erased elements - erased element is between two skipblocks\r\n\t\t\t{\r\n\t\t\t\tconst skipfield_type preceding_value = *(it.skipfield_pointer - 1);\r\n\t\t\t\tconst skipfield_type following_value = static_cast<skipfield_type>(*(it.skipfield_pointer + 1) + 1);\r\n\r\n\t\t\t\t// Join the skipblocks\r\n\t\t\t\t*(it.skipfield_pointer - preceding_value) = *(it.skipfield_pointer + following_value - 1) = static_cast<skipfield_type>(preceding_value + following_value);\r\n\r\n\t\t\t\t// Remove the following skipblock's entry from the free list\r\n\t\t\t\tconst skipfield_type following_previous = *(reinterpret_cast<skipfield_pointer_type>(it.element_pointer + 1));\r\n\t\t\t\tconst skipfield_type following_next = *(reinterpret_cast<skipfield_pointer_type>(it.element_pointer + 1) + 1);\r\n\r\n\t\t\t\tif (following_previous != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.group_pointer->elements + following_previous) + 1) = following_next; // Set next index of previous free list node to this node's 'next' index\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (following_next != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(it.group_pointer->elements + following_next)) = following_previous; // Set previous index of next free list node to this node's 'previous' index\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tit.group_pointer->free_list_head = following_previous;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tupdate_value = following_value;\r\n\t\t\t}\r\n\r\n\t\t\titerator return_iterator(it.group_pointer, it.element_pointer + update_value, it.skipfield_pointer + update_value);\r\n\r\n\t\t\tif (return_iterator.element_pointer == it.group_pointer->last_endpoint && it.group_pointer->next_group != NULL)\r\n\t\t\t{\r\n\t\t\t\treturn_iterator.group_pointer = it.group_pointer->next_group;\r\n\t\t\t\tconst aligned_pointer_type elements = return_iterator.group_pointer->elements;\r\n\t\t\t\tconst skipfield_pointer_type skipfield = return_iterator.group_pointer->skipfield;\r\n\t\t\t\tconst skipfield_type skip = *skipfield;\r\n\t\t\t\treturn_iterator.element_pointer = elements + skip;\r\n\t\t\t\treturn_iterator.skipfield_pointer = skipfield + skip;\r\n\t\t\t}\r\n\r\n\t\t\tif (it.element_pointer == begin_iterator.element_pointer) // If original iterator was first element in colony, update it's value with the next non-erased element:\r\n\t\t\t{\r\n\t\t\t\tbegin_iterator = return_iterator;\r\n\t\t\t}\r\n\r\n\t\t\treturn return_iterator;\r\n\t\t}\r\n\r\n\t\t// else: group is empty, consolidate groups\r\n\t\tconst bool in_back_block = (it.group_pointer->next_group == NULL), in_front_block = (it.group_pointer == begin_iterator.group_pointer);\r\n\r\n\t\tif (in_back_block & in_front_block) // ie. only group in colony\r\n\t\t{\r\n\t\t\t// Reset skipfield and free list rather than clearing - leads to fewer allocations/deallocations:\r\n\t\t\treset_only_group_left(it.group_pointer);\r\n\t\t\treturn end_iterator;\r\n\t\t}\r\n\t\telse if ((!in_back_block) & in_front_block) // ie. Remove first group, change first group to next group\r\n\t\t{\r\n\t\t\tit.group_pointer->next_group->previous_group = NULL; // Cut off this group from the chain\r\n\t\t\tbegin_iterator.group_pointer = it.group_pointer->next_group; // Make the next group the first group\r\n\r\n\t\t\tupdate_subsequent_group_numbers(begin_iterator.group_pointer);\r\n\r\n\t\t\tif (it.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max()) // Erasures present within the group, ie. was part of the linked list of groups with erasures.\r\n\t\t\t{\r\n\t\t\t\tremove_from_groups_with_erasures_list(it.group_pointer);\r\n\t\t\t}\r\n\r\n\t\t\ttotal_capacity -= it.group_pointer->capacity;\r\n\t\t\tdeallocate_group(it.group_pointer);\r\n\r\n\t\t\t// note: end iterator only needs to be changed if the deleted group was the final group in the chain ie. not in this case\r\n\t\t\tbegin_iterator.element_pointer = begin_iterator.group_pointer->elements + *(begin_iterator.group_pointer->skipfield); // If the beginning index has been erased (ie. skipfield != 0), skip to next non-erased element\r\n\t\t\tbegin_iterator.skipfield_pointer = begin_iterator.group_pointer->skipfield + *(begin_iterator.group_pointer->skipfield);\r\n\r\n\t\t\treturn begin_iterator;\r\n\t\t}\r\n\t\telse if (!(in_back_block | in_front_block)) // this is a non-first group but not final group in chain: delete the group, then link previous group to the next group in the chain:\r\n\t\t{\r\n\t\t\tit.group_pointer->next_group->previous_group = it.group_pointer->previous_group;\r\n\t\t\tconst group_pointer_type return_group = it.group_pointer->previous_group->next_group = it.group_pointer->next_group; // close the chain, removing this group from it\r\n\r\n\t\t\tupdate_subsequent_group_numbers(return_group);\r\n\r\n\t\t\tif (it.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t{\r\n\t\t\t\tremove_from_groups_with_erasures_list(it.group_pointer);\r\n\t\t\t}\r\n\r\n\t\t\tif (it.group_pointer->next_group != end_iterator.group_pointer)\r\n\t\t\t{\r\n\t\t\t\ttotal_capacity -= it.group_pointer->capacity;\r\n\t\t\t\tdeallocate_group(it.group_pointer);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tadd_group_to_unused_groups_list(it.group_pointer);\r\n\t\t\t}\r\n\r\n\t\t\t// Return next group's first non-erased element:\r\n\t\t\treturn iterator(return_group, return_group->elements + *(return_group->skipfield), return_group->skipfield + *(return_group->skipfield));\r\n\t\t}\r\n\t\telse // this is a non-first group and the final group in the chain\r\n\t\t{\r\n\t\t\tif (it.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t{\r\n\t\t\t\tremove_from_groups_with_erasures_list(it.group_pointer);\r\n\t\t\t}\r\n\r\n\t\t\tit.group_pointer->previous_group->next_group = NULL;\r\n\t\t\tend_iterator.group_pointer = it.group_pointer->previous_group; // end iterator needs to be changed as element supplied was the back element of the colony\r\n\t\t\tend_iterator.element_pointer = reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield);\r\n\t\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + end_iterator.group_pointer->capacity;\r\n\r\n\t\t\tadd_group_to_unused_groups_list(it.group_pointer);\r\n\r\n\t\t\treturn end_iterator;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\t// Range erase:\r\n\r\n\titerator erase(const const_iterator iterator1, const const_iterator iterator2)\t// if uninitialized/invalid iterators supplied, function could generate an exception. If iterator1 > iterator2, behaviour is undefined.\r\n\t{\r\n\t\tassert(iterator1 <= iterator2);\r\n\r\n\t\tconst_iterator current = iterator1;\r\n\r\n\t\tif (current.group_pointer != iterator2.group_pointer) // ie. if start and end iterators are in separate groups\r\n\t\t{\r\n\t\t\tif (current.element_pointer != current.group_pointer->elements + *(current.group_pointer->skipfield)) // if iterator1 is not the first non-erased element in it's group - most common case\r\n\t\t\t{\r\n\t\t\t\tsize_type number_of_group_erasures = 0;\r\n\r\n\t\t\t\t// Now update skipfield:\r\n\t\t\t\tconst aligned_pointer_type end = iterator1.group_pointer->last_endpoint;\r\n\r\n\t\t\t\t// Schema: first erase all non-erased elements until end of group & remove all skipblocks post-iterator1 from the free_list. Then, either update preceding skipblock or create new one:\r\n\r\n\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT // if trivially-destructible, and C++11 or higher, and no erasures in group, skip while loop below and just jump straight to the location\r\n\t\t\t\t\tif (std::is_trivially_destructible<element_type>::value && current.group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tnumber_of_group_erasures += static_cast<size_type>(end - current.element_pointer);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t#endif\r\n\t\t\t\t{\r\n\t\t\t\t\twhile (current.element_pointer != end)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif (*current.skipfield_pointer == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer)); // Destruct element\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t++number_of_group_erasures;\r\n\t\t\t\t\t\t\t++current.element_pointer;\r\n\t\t\t\t\t\t\t++current.skipfield_pointer;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse // remove skipblock from group:\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tconst skipfield_type prev_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(current.element_pointer));\r\n\t\t\t\t\t\t\tconst skipfield_type next_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(current.element_pointer) + 1);\r\n\r\n\t\t\t\t\t\t\tcurrent.element_pointer += *(current.skipfield_pointer);\r\n\t\t\t\t\t\t\tcurrent.skipfield_pointer += *(current.skipfield_pointer);\r\n\r\n\t\t\t\t\t\t\tif (next_free_list_index == std::numeric_limits<skipfield_type>::max() && prev_free_list_index == std::numeric_limits<skipfield_type>::max()) // if this is the last skipblock in the free list\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tremove_from_groups_with_erasures_list(iterator1.group_pointer); // remove group from list of free-list groups - will be added back in down below, but not worth optimizing for\r\n\t\t\t\t\t\t\t\titerator1.group_pointer->free_list_head = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t\t\t\t\tnumber_of_group_erasures += static_cast<size_type>(end - current.element_pointer);\r\n\r\n\t\t\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\twhile (current.element_pointer != end) // miniloop - avoid checking skipfield for rest of elements in group, as there are no more skipped elements now\r\n\t\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer++)); // Destruct element\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tbreak; // end overall while loop\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse if (next_free_list_index == std::numeric_limits<skipfield_type>::max()) // if this is the head of the free list\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\tcurrent.group_pointer->free_list_head = prev_free_list_index; // make free list head equal to next free list node\r\n\t\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + prev_free_list_index) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\telse // either a tail or middle free list node\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + next_free_list_index)) = prev_free_list_index;\r\n\r\n\t\t\t\t\t\t\t\tif (prev_free_list_index != std::numeric_limits<skipfield_type>::max()) // ie. not the tail free list node\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + prev_free_list_index) + 1) = next_free_list_index;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tconst skipfield_type previous_node_value = *(iterator1.skipfield_pointer - 1);\r\n\t\t\t\tconst skipfield_type distance_to_end = static_cast<skipfield_type>(end - iterator1.element_pointer);\r\n\r\n\r\n\t\t\t\tif (previous_node_value == 0) // no previous skipblock\r\n\t\t\t\t{\r\n\t\t\t\t\t*iterator1.skipfield_pointer = distance_to_end; // set start node value\r\n\t\t\t\t\t*(iterator1.skipfield_pointer + distance_to_end - 1) = distance_to_end; // set end node value\r\n\r\n\t\t\t\t\tconst skipfield_type index = static_cast<skipfield_type>(iterator1.element_pointer - iterator1.group_pointer->elements);\r\n\r\n\t\t\t\t\tif (iterator1.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max()) // ie. if this group already has some erased elements\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(iterator1.group_pointer->elements + iterator1.group_pointer->free_list_head) + 1) = index; // set prev free list head's 'next index' number to the index of the iterator1 element\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\titerator1.group_pointer->erasures_list_next_group = groups_with_erasures_list_head; // add it to the groups-with-erasures free list\r\n\t\t\t\t\t\tgroups_with_erasures_list_head = iterator1.group_pointer;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(iterator1.element_pointer)) = iterator1.group_pointer->free_list_head;\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(iterator1.element_pointer) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t\titerator1.group_pointer->free_list_head = index;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{ // update previous skipblock, no need to update free list:\r\n\t\t\t\t\t*(iterator1.skipfield_pointer - previous_node_value) = *(iterator1.skipfield_pointer + distance_to_end - 1) = static_cast<skipfield_type>(previous_node_value + distance_to_end);\r\n\t\t\t\t}\r\n\r\n\t\t\t\titerator1.group_pointer->size = static_cast<skipfield_type>(iterator1.group_pointer->size - number_of_group_erasures);\r\n\t\t\t\ttotal_size -= number_of_group_erasures;\r\n\r\n\t\t\t\tcurrent.group_pointer = current.group_pointer->next_group;\r\n\t\t\t}\r\n\r\n\r\n\t\t\t// Intermediate groups:\r\n\t\t\tconst group_pointer_type previous_group = current.group_pointer->previous_group;\r\n\r\n\t\t\twhile (current.group_pointer != iterator2.group_pointer)\r\n\t\t\t{\r\n\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t\t#endif\r\n\t\t\t\t{\r\n\t\t\t\t\tcurrent.element_pointer = current.group_pointer->elements + *(current.group_pointer->skipfield);\r\n\t\t\t\t\tcurrent.skipfield_pointer = current.group_pointer->skipfield + *(current.group_pointer->skipfield);\r\n\t\t\t\t\tconst aligned_pointer_type end = current.group_pointer->last_endpoint;\r\n\r\n\t\t\t\t\tdo\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer)); // Destruct element\r\n\t\t\t\t\t\tconst skipfield_type skip = *(++current.skipfield_pointer);\r\n\t\t\t\t\t\tcurrent.element_pointer += static_cast<size_type>(skip) + 1u;\r\n\t\t\t\t\t\tcurrent.skipfield_pointer += skip;\r\n\t\t\t\t\t} while (current.element_pointer != end);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (current.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\tremove_from_groups_with_erasures_list(current.group_pointer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttotal_size -= current.group_pointer->size;\r\n\t\t\t\tconst group_pointer_type current_group = current.group_pointer;\r\n\t\t\t\tcurrent.group_pointer = current.group_pointer->next_group;\r\n\r\n\t\t\t\tif (current_group != end_iterator.group_pointer && current_group->next_group != end_iterator.group_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\ttotal_capacity -= current_group->capacity;\r\n\t\t\t\t\tdeallocate_group(current_group);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tadd_group_to_unused_groups_list(current_group);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tcurrent.element_pointer = current.group_pointer->elements + *(current.group_pointer->skipfield);\r\n\t\t\tcurrent.skipfield_pointer = current.group_pointer->skipfield + *(current.group_pointer->skipfield);\r\n\t\t\tcurrent.group_pointer->previous_group = previous_group;\r\n\r\n\t\t\tif (previous_group != NULL)\r\n\t\t\t{\r\n\t\t\t\tprevious_group->next_group = current.group_pointer;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tbegin_iterator = iterator2; // This line is included here primarily to avoid a secondary if statement within the if block below - it will not be needed in any other situation\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (current.element_pointer == iterator2.element_pointer) // in case iterator2 was at beginning of it's group - also covers empty range case (first == last)\r\n\t\t{\r\n\t\t\treturn iterator2;\r\n\t\t}\r\n\r\n\t\t// Final group:\r\n\t\t// Code explanation:\r\n\t\t// If not erasing entire final group, 1. Destruct elements (if non-trivial destructor) and add locations to group free list. 2. process skipfield.\r\n\t\t// If erasing entire group, 1. Destruct elements (if non-trivial destructor), 2. if no elements left in colony, clear() 3. otherwise reset end_iterator and remove group from groups-with-erasures list (if free list of erasures present)\r\n\r\n\t\tif (iterator2.element_pointer != end_iterator.element_pointer || current.element_pointer != current.group_pointer->elements + *(current.group_pointer->skipfield)) // ie. not erasing entire group\r\n\t\t{\r\n\t\t\tsize_type number_of_group_erasures = 0;\r\n\t\t\t// Schema: first erased all non-erased elements until end of group & remove all skipblocks post-iterator2 from the free_list. Then, either update preceding skipblock or create new one:\r\n\r\n\t\t\tconst const_iterator current_saved = current;\r\n\r\n\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT // if trivially-destructible, and C++11 or higher, and no erasures in group, skip while loop below and just jump straight to the location\r\n\t\t\t\tif (std::is_trivially_destructible<element_type>::value && current.group_pointer->free_list_head == std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\tnumber_of_group_erasures += static_cast<size_type>(iterator2.element_pointer - current.element_pointer);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t#endif\r\n\t\t\t{\r\n\t\t\t\twhile (current.element_pointer != iterator2.element_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (*current.skipfield_pointer == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer)); // Destruct element\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t++number_of_group_erasures;\r\n\t\t\t\t\t\t++current.element_pointer;\r\n\t\t\t\t\t\t++current.skipfield_pointer;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse // remove skipblock from group:\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tconst skipfield_type prev_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(current.element_pointer));\r\n\t\t\t\t\t\tconst skipfield_type next_free_list_index = *(reinterpret_cast<skipfield_pointer_type>(current.element_pointer) + 1);\r\n\r\n\t\t\t\t\t\tcurrent.element_pointer += *(current.skipfield_pointer);\r\n\t\t\t\t\t\tcurrent.skipfield_pointer += *(current.skipfield_pointer);\r\n\r\n\t\t\t\t\t\tif (next_free_list_index == std::numeric_limits<skipfield_type>::max() && prev_free_list_index == std::numeric_limits<skipfield_type>::max()) // if this is the last skipblock in the free list\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tremove_from_groups_with_erasures_list(iterator2.group_pointer); // remove group from list of free-list groups - will be added back in down below, but not worth optimizing for\r\n\t\t\t\t\t\t\titerator2.group_pointer->free_list_head = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t\t\t\tnumber_of_group_erasures += static_cast<size_type>(iterator2.element_pointer - current.element_pointer);\r\n\r\n\t\t\t\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\t\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t\t\t\t\t#endif\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\twhile (current.element_pointer != iterator2.element_pointer)\r\n\t\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer++)); // Destruct element\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tbreak; // end overall while loop\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if (next_free_list_index == std::numeric_limits<skipfield_type>::max()) // if this is the head of the free list\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tcurrent.group_pointer->free_list_head = prev_free_list_index;\r\n\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + prev_free_list_index) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + next_free_list_index)) = prev_free_list_index;\r\n\r\n\t\t\t\t\t\t\tif (prev_free_list_index != std::numeric_limits<skipfield_type>::max()) // ie. not the tail free list node\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current.group_pointer->elements + prev_free_list_index) + 1) = next_free_list_index;\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\r\n\t\t\tconst skipfield_type distance_to_iterator2 = static_cast<skipfield_type>(iterator2.element_pointer - current_saved.element_pointer);\r\n\t\t\tconst skipfield_type index = static_cast<skipfield_type>(current_saved.element_pointer - iterator2.group_pointer->elements);\r\n\r\n\r\n\t\t\tif (index == 0 || *(current_saved.skipfield_pointer - 1) == 0) // element is either at start of group or previous skipfield node is 0\r\n\t\t\t{\r\n\t\t\t\t*(current_saved.skipfield_pointer) = distance_to_iterator2;\r\n\t\t\t\t*(iterator2.skipfield_pointer - 1) = distance_to_iterator2;\r\n\r\n\t\t\t\tif (iterator2.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max()) // ie. if this group already has some erased elements\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(iterator2.group_pointer->elements + iterator2.group_pointer->free_list_head) + 1) = index;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\titerator2.group_pointer->erasures_list_next_group = groups_with_erasures_list_head; // add it to the groups-with-erasures free list\r\n\t\t\t\t\tgroups_with_erasures_list_head = iterator2.group_pointer;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current_saved.element_pointer)) = iterator2.group_pointer->free_list_head;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(current_saved.element_pointer) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\titerator2.group_pointer->free_list_head = index;\r\n\t\t\t}\r\n\t\t\telse // If iterator 1 & 2 are in same group, but iterator 1 was not at start of group, and previous skipfield node is an end node in a skipblock:\r\n\t\t\t{\r\n\t\t\t\t// Just update existing skipblock, no need to create new free list node:\r\n\t\t\t\tconst skipfield_type prev_node_value = *(current_saved.skipfield_pointer - 1);\r\n\t\t\t\t*(current_saved.skipfield_pointer - prev_node_value) = static_cast<skipfield_type>(prev_node_value + distance_to_iterator2);\r\n\t\t\t\t*(iterator2.skipfield_pointer - 1) = static_cast<skipfield_type>(prev_node_value + distance_to_iterator2);\r\n\t\t\t}\r\n\r\n\r\n\t\t\tif (iterator1.element_pointer == begin_iterator.element_pointer)\r\n\t\t\t{\r\n\t\t\t\tbegin_iterator = iterator2;\r\n\t\t\t}\r\n\r\n\t\t\titerator2.group_pointer->size = static_cast<skipfield_type>(iterator2.group_pointer->size - number_of_group_erasures);\r\n\t\t\ttotal_size -= number_of_group_erasures;\r\n\t\t}\r\n\t\telse // ie. full group erasure\r\n\t\t{\r\n\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t\t#endif\r\n\t\t\t{\r\n\t\t\t\twhile(current.element_pointer != iterator2.element_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer));\r\n\t\t\t\t\t++current.skipfield_pointer;\r\n\t\t\t\t\tcurrent.element_pointer += static_cast<size_type>(*current.skipfield_pointer) + 1u;\r\n\t\t\t\t\tcurrent.skipfield_pointer += *current.skipfield_pointer;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\r\n\t\t\tif ((total_size -= current.group_pointer->size) != 0) // ie. either previous_group != NULL or next_group != NULL\r\n\t\t\t{\r\n\t\t\t\tif (current.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max())\r\n\t\t\t\t{\r\n\t\t\t\t\tremove_from_groups_with_erasures_list(current.group_pointer);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcurrent.group_pointer->previous_group->next_group = current.group_pointer->next_group;\r\n\r\n\t\t\t\tif (current.group_pointer == end_iterator.group_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\tend_iterator.group_pointer = current.group_pointer->previous_group;\r\n\t\t\t\t\tend_iterator.element_pointer = end_iterator.group_pointer->last_endpoint;\r\n\t\t\t\t\tend_iterator.skipfield_pointer = end_iterator.group_pointer->skipfield + end_iterator.group_pointer->capacity;\r\n\t\t\t\t\tadd_group_to_unused_groups_list(current.group_pointer);\r\n\t\t\t\t\treturn end_iterator;\r\n\t\t\t\t}\r\n\t\t\t\telse if (current.group_pointer == begin_iterator.group_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\tbegin_iterator.group_pointer = current.group_pointer->next_group;\r\n\t\t\t\t\tconst skipfield_type skip = *(begin_iterator.group_pointer->skipfield);\r\n\t\t\t\t\tbegin_iterator.element_pointer = begin_iterator.group_pointer->elements + skip;\r\n\t\t\t\t\tbegin_iterator.skipfield_pointer = begin_iterator.group_pointer->skipfield + skip;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (current.group_pointer->next_group != end_iterator.group_pointer)\r\n\t\t\t\t{\r\n\t\t\t\t\ttotal_capacity -= current.group_pointer->capacity;\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tadd_group_to_unused_groups_list(current.group_pointer);\r\n\t\t\t\t\treturn iterator2;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\telse // ie. colony is now empty\r\n\t\t\t{\r\n\t\t\t\t// Reset skipfield and free list rather than clearing - leads to fewer allocations/deallocations:\r\n\t\t\t\treset_only_group_left(current.group_pointer);\r\n\t\t\t\treturn end_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tdeallocate_group(current.group_pointer);\r\n\t\t}\r\n\r\n\t\treturn iterator2;\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\tvoid prepare_groups_for_assign(const size_type size)\r\n\t{\r\n\t\t// Destroy all elements if non-trivial:\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (!std::is_trivially_destructible<element_type>::value)\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tfor (iterator current = begin_iterator; current != end_iterator; ++current)\r\n\t\t\t{\r\n\t\t\t\tPLF_DESTROY(allocator_type, *this, reinterpret_cast<pointer>(current.element_pointer));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (size < total_capacity && (total_capacity - size) >= tuple_allocator_pair.min_group_capacity)\r\n\t\t{\r\n\t\t\tsize_type difference = total_capacity - size;\r\n\t\t\tend_iterator.group_pointer->next_group = unused_groups_head;\r\n\r\n\t\t\t// Remove surplus groups which're under the difference limit:\r\n\t\t\tgroup_pointer_type current_group = begin_iterator.group_pointer, previous_group = NULL;\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\tconst group_pointer_type next_group = current_group->next_group;\r\n\r\n\t\t\t\tif (current_group->capacity <= difference)\r\n\t\t\t\t{ // Remove group:\r\n\t\t\t\t\tdifference -= current_group->capacity;\r\n\t\t\t\t\ttotal_capacity -= current_group->capacity;\r\n\t\t\t\t\tdeallocate_group(current_group);\r\n\r\n\t\t\t\t\tif (current_group == begin_iterator.group_pointer)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tbegin_iterator.group_pointer = next_group;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tif (previous_group != NULL)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprevious_group->next_group = current_group;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tprevious_group = current_group;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcurrent_group = next_group;\r\n\t\t\t} while (current_group != NULL);\r\n\r\n\t\t\tprevious_group->next_group = NULL;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tif (size > total_capacity)\r\n\t\t\t{\r\n\t\t\t\treserve(size);\r\n\t\t\t}\r\n\r\n\t\t\t// Join all unused_groups to main chain:\r\n\t\t\tend_iterator.group_pointer->next_group = unused_groups_head;\r\n\t\t}\r\n\r\n\t\tbegin_iterator.element_pointer = begin_iterator.group_pointer->elements;\r\n\t\tbegin_iterator.skipfield_pointer = begin_iterator.group_pointer->skipfield;\r\n  \t\tgroups_with_erasures_list_head = NULL;\r\n\t\ttotal_size = 0;\r\n\t}\r\n\r\n\r\npublic:\r\n\r\n\r\n\t// Fill assign:\r\n\r\n\tinline void assign(const size_type size, const element_type &element)\r\n\t{\r\n\t\tif (size == 0)\r\n\t\t{\r\n\t\t\tclear();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tprepare_groups_for_assign(size);\r\n\t\tfill_unused_groups(size, element, 0, NULL, begin_iterator.group_pointer);\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\t// Range assign core:\r\n\r\n\ttemplate <class iterator_type>\r\n\tinline void range_assign(const iterator_type it, const size_type size)\r\n\t{\r\n\t\tif (size == 0)\r\n\t\t{\r\n\t\t\tclear();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tprepare_groups_for_assign(size);\r\n\t\trange_fill_unused_groups(size, it, 0, NULL, begin_iterator.group_pointer);\r\n\t}\r\n\r\n\r\n\r\n\r\npublic:\r\n\r\n\t// Range assign:\r\n\r\n\ttemplate <class iterator_type>\r\n\tinline void assign(const typename plf_enable_if_c<!std::numeric_limits<iterator_type>::is_integer, iterator_type>::type first, const iterator_type last)\r\n\t{\r\n\t\tusing std::distance;\r\n\t\trange_assign(first, static_cast<size_type>(distance(first,last)));\r\n\t}\r\n\r\n\r\n\r\n\t// Range insert for differing iterator types eg. sentinels:\r\n\r\n\t#ifdef PLF_CPP20_SUPPORT\r\n\t\ttemplate <class iterator_type1, class iterator_type2>\r\n\t\t\trequires (!std::same_as<iterator_type1, iterator_type2> && std::equality_comparable_with<iterator_type1, iterator_type2> && !std::integral<iterator_type1> && !std::integral<iterator_type2>)\r\n\t\tinline void assign (const iterator_type1 first, const iterator_type2 last)\r\n\t\t{\r\n\t\t\tsize_type distance = 0;\r\n\t\t\tfor(iterator_type1 current = first; current != last; ++current, ++distance) {};\r\n\t\t\trange_assign(first, distance);\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t// Range assign, move_iterator overload:\r\n\r\n\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\ttemplate <class iterator_type>\r\n\t\tinline void assign (const std::move_iterator<iterator_type> first, const std::move_iterator<iterator_type> last)\r\n\t\t{\r\n\t\t\tusing std::distance;\r\n\t\t\trange_assign(first, static_cast<size_type>(distance(first.base(),last.base())));\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t// Initializer-list assign:\r\n\r\n\t#ifdef PLF_INITIALIZER_LIST_SUPPORT\r\n\t\tinline void assign(const std::initializer_list<element_type> &element_list)\r\n\t\t{\r\n\t\t\trange_assign(element_list.begin(), static_cast<size_type>(element_list.size()));\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\r\n\t#ifdef PLF_CPP20_SUPPORT\r\n\t\t[[nodiscard]]\r\n\t#endif\r\n\tinline PLF_FORCE_INLINE bool empty() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn total_size == 0;\r\n\t}\r\n\r\n\r\n\r\n\tinline size_type size() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn total_size;\r\n\t}\r\n\r\n\r\n\r\n\t#ifdef PLF_COLONY_TEST_DEBUG // used for debugging during internal testing only:\r\n\t\tsize_type group_size_sum() const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\tsize_type temp = 0;\r\n\r\n\t\t\tfor (group_pointer_type current = begin_iterator.group_pointer; current != NULL; current = current->next_group)\r\n\t\t\t{\r\n\t\t\t\ttemp += current->size;\r\n\t\t\t}\r\n\r\n\t\t\treturn temp;\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\tinline size_type max_size() const PLF_NOEXCEPT\r\n\t{\r\n\t\t#ifdef PLF_ALLOCATOR_TRAITS_SUPPORT\r\n\t\t\treturn std::allocator_traits<allocator_type>::max_size(*this);\r\n\t\t#else\r\n\t\t\treturn allocator_type::max_size();\r\n\t\t#endif\r\n\t}\r\n\r\n\r\n\r\n\tinline size_type capacity() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn total_capacity;\r\n\t}\r\n\r\n\r\n\r\n\tinline size_type memory() const PLF_NOEXCEPT\r\n\t{\r\n\t\tsize_type memory_use = sizeof(*this); // sizeof colony basic structure\r\n\t\tend_iterator.group_pointer->next_group = unused_groups_head; // temporarily link the main groups and unused groups (reserved groups) in order to only have one loop below instead of several\r\n\r\n\t\tfor(group_pointer_type current = begin_iterator.group_pointer; current != NULL; current = current->next_group)\r\n\t\t{\r\n\t\t\tmemory_use += sizeof(group) + (PLF_GROUP_ALIGNED_BLOCK_SIZE(current->capacity) * sizeof(aligned_allocation_struct)); // add memory block sizes and the size of the group structs themselves. The original calculation, including divisor, is necessary in order to correctly round up the number of allocations\r\n\t\t}\r\n\r\n\t\tend_iterator.group_pointer->next_group = NULL; // unlink main groups and unused groups\r\n\t\treturn memory_use;\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\t// get all elements contiguous in memory and shrink to fit, remove erasures and erasure free lists. Invalidates all iterators and pointers to elements.\r\n\tvoid consolidate()\r\n\t{\r\n\t\t#if defined(PLF_MOVE_SEMANTICS_SUPPORT) && defined(PLF_TYPE_TRAITS_SUPPORT)\r\n\t\t\tif PLF_CONSTEXPR (std::is_move_constructible<element_type>::value && std::is_move_assignable<element_type>::value)\r\n\t\t\t{\r\n\t\t\t\tcolony temp(plf::colony_limits(tuple_allocator_pair.min_group_capacity, group_allocator_pair.max_group_capacity));\r\n\t\t\t\ttemp.range_assign(std::make_move_iterator(begin_iterator), total_size);\r\n\t\t\t\t*this = std::move(temp); // Avoid generating 2nd temporary\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tcolony temp(*this);\r\n\t\t\tswap(temp);\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\r\npublic:\r\n\r\n\r\n\tvoid reshape(const plf::colony_limits capacities)\r\n\t{\r\n\t\tcheck_capacities_conformance(capacities);\r\n\t\ttuple_allocator_pair.min_group_capacity = static_cast<skipfield_type>(capacities.min);\r\n\t\tgroup_allocator_pair.max_group_capacity = static_cast<skipfield_type>(capacities.max);\r\n\r\n\t\t// Need to check all group sizes here, because splice might append smaller blocks to the end of a larger block:\r\n\t\tfor (group_pointer_type current = begin_iterator.group_pointer; current != end_iterator.group_pointer; current = current->next_group)\r\n\t\t{\r\n\t\t\tif (current->capacity < tuple_allocator_pair.min_group_capacity || current->capacity > group_allocator_pair.max_group_capacity)\r\n\t\t\t{\r\n\t\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT // If type is non-copyable/movable, cannot be consolidated, throw exception:\r\n\t\t\t\t\tif PLF_CONSTEXPR (!(std::is_copy_constructible<element_type>::value || std::is_move_constructible<element_type>::value))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthrow;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t#endif\r\n\t\t\t\t{\r\n\t\t\t\t\tconsolidate();\r\n\t\t\t\t}\r\n\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\tinline plf::colony_limits block_limits() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn plf::colony_limits(static_cast<size_t>(tuple_allocator_pair.min_group_capacity), static_cast<size_t>(group_allocator_pair.max_group_capacity));\r\n\t}\r\n\r\n\r\n\r\n\tinline PLF_FORCE_INLINE void clear() PLF_NOEXCEPT\r\n\t{\r\n\t\tdestroy_all_data();\r\n\t\tblank();\r\n\t}\r\n\r\n\r\n\r\n\tinline colony & operator = (const colony &source)\r\n\t{\r\n\t\tassert(&source != this);\r\n\t\trange_assign(source.begin_iterator, source.total_size);\r\n\t\treturn *this;\r\n\t}\r\n\r\n\r\n\r\n\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t// Move assignment\r\n\t\tcolony & operator = (colony &&source) PLF_NOEXCEPT_MOVE_ASSIGN(allocator_type)\r\n\t\t{\r\n\t\t\tassert(&source != this);\r\n\t\t\tdestroy_all_data();\r\n\r\n\t\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\t\tif PLF_CONSTEXPR (std::is_trivial<group_pointer_type>::value && std::is_trivial<aligned_pointer_type>::value && std::is_trivial<skipfield_pointer_type>::value)\r\n\t\t\t\t{\r\n\t\t\t\t\tstd::memcpy(static_cast<void *>(this), &source, sizeof(colony));\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t#endif\r\n\t\t\t{\r\n\t\t\t\tend_iterator = std::move(source.end_iterator);\r\n\t\t\t\tbegin_iterator = std::move(source.begin_iterator);\r\n\t\t\t\tgroups_with_erasures_list_head = std::move(source.groups_with_erasures_list_head);\r\n\t\t\t\tunused_groups_head =  std::move(source.unused_groups_head);\r\n\t\t\t\ttotal_size = source.total_size;\r\n\t\t\t\ttotal_capacity = source.total_capacity;\r\n\t\t\t\ttuple_allocator_pair.min_group_capacity = source.tuple_allocator_pair.min_group_capacity;\r\n\t\t\t\tgroup_allocator_pair.max_group_capacity = source.group_allocator_pair.max_group_capacity;\r\n\t\t\t}\r\n\r\n\t\t\tsource.blank();\r\n\t\t\treturn *this;\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\t#ifdef PLF_INITIALIZER_LIST_SUPPORT\r\n\t\tinline colony & operator = (const std::initializer_list<element_type> &element_list)\r\n\t\t{\r\n\t\t\trange_assign(element_list.begin(), static_cast<size_type>(element_list.size()));\r\n\t\t\treturn *this;\r\n\t\t}\r\n\t#endif\r\n\r\n\r\n\r\n\tfriend bool operator == (const colony &lh, const colony &rh)\r\n\t{\r\n\t\tif (lh.total_size != rh.total_size)\r\n\t\t{\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\tfor (const_iterator lh_iterator = lh.begin_iterator, rh_iterator = rh.begin_iterator; lh_iterator != lh.end_iterator; ++lh_iterator, ++rh_iterator)\r\n\t\t{\r\n\t\t\tif (*lh_iterator != *rh_iterator)\r\n\t\t\t{\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\r\n\r\n\tfriend bool operator != (const colony &lh, const colony &rh)\r\n\t{\r\n\t\treturn !(lh == rh);\r\n\t}\r\n\r\n\r\n\r\n\tvoid shrink_to_fit()\r\n\t{\r\n\t\tif (total_size == total_capacity)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if (total_size == 0)\r\n\t\t{\r\n\t\t\tclear();\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tconsolidate();\r\n\t}\r\n\r\n\r\n\r\n\tvoid trim() PLF_NOEXCEPT\r\n\t{\r\n\t\twhile(unused_groups_head != NULL)\r\n\t\t{\r\n\t\t\ttotal_capacity -= unused_groups_head->capacity;\r\n\t\t\tconst group_pointer_type next_group = unused_groups_head->next_group;\r\n\t\t\tdeallocate_group(unused_groups_head);\r\n\t\t\tunused_groups_head = next_group;\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\n\tvoid reserve(size_type new_capacity)\r\n\t{\r\n\t\tif (new_capacity == 0 || new_capacity <= total_capacity) // We already have enough space allocated\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (new_capacity > max_size())\r\n\t\t{\r\n\t\t\tthrow std::length_error(\"Capacity requested via reserve() greater than max_size()\");\r\n\t\t}\r\n\r\n\t\tnew_capacity -= total_capacity;\r\n\r\n\t\tsize_type number_of_max_groups = new_capacity / group_allocator_pair.max_group_capacity;\r\n\t\tskipfield_type remainder = static_cast<skipfield_type>(new_capacity - (number_of_max_groups * group_allocator_pair.max_group_capacity));\r\n\r\n\r\n\t\tif (remainder == 0)\r\n\t\t{\r\n\t\t\tremainder = group_allocator_pair.max_group_capacity;\r\n\t\t\t--number_of_max_groups;\r\n\t\t}\r\n\t\telse if (remainder < tuple_allocator_pair.min_group_capacity)\r\n\t\t{\r\n\t\t\tremainder = tuple_allocator_pair.min_group_capacity;\r\n\t\t}\r\n\r\n\r\n\t\tgroup_pointer_type current_group, first_unused_group;\r\n\r\n\t\tif (begin_iterator.group_pointer == NULL) // Most common scenario - empty colony\r\n\t\t{\r\n\t\t\tinitialize(remainder);\r\n\t\t\tbegin_iterator.group_pointer->last_endpoint = begin_iterator.group_pointer->elements; // last_endpoint initially == elements + 1 via default constructor\r\n\t\t\tbegin_iterator.group_pointer->size = 0; // 1 by default\r\n\r\n\t\t\tif (number_of_max_groups == 0)\r\n\t\t\t{\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tfirst_unused_group = current_group = allocate_new_group(group_allocator_pair.max_group_capacity, begin_iterator.group_pointer);\r\n\t\t\t\ttotal_capacity += group_allocator_pair.max_group_capacity;\r\n\t\t\t\t--number_of_max_groups;\r\n\t\t\t}\r\n\t\t}\r\n\t\telse // Non-empty colony, add first group:\r\n\t\t{\r\n\t\t\tfirst_unused_group = current_group = allocate_new_group(remainder, end_iterator.group_pointer);\r\n\t\t\ttotal_capacity += remainder;\r\n\t\t}\r\n\r\n\r\n\t\twhile (number_of_max_groups != 0)\r\n\t\t{\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\tcurrent_group->next_group = allocate_new_group(group_allocator_pair.max_group_capacity, current_group);\r\n\t\t\t}\r\n\t\t\tcatch (...)\r\n\t\t\t{\r\n\t\t\t\tdeallocate_group(current_group->next_group);\r\n\t\t\t\tcurrent_group->next_group = unused_groups_head;\r\n\t\t\t\tunused_groups_head = first_unused_group;\r\n\t\t\t\tthrow;\r\n\t\t\t}\r\n\r\n\t\t\tcurrent_group = current_group->next_group;\r\n\t\t\ttotal_capacity += group_allocator_pair.max_group_capacity;\r\n\t\t\t--number_of_max_groups;\r\n\t\t}\r\n\r\n\t\tcurrent_group->next_group = unused_groups_head;\r\n\t\tunused_groups_head = first_unused_group;\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\ttemplate <bool is_const>\r\n\tcolony_iterator<is_const> get_it(const pointer element_pointer) const PLF_NOEXCEPT\r\n\t{\r\n\t\ttypedef colony_iterator<is_const> iterator_type;\r\n\r\n\t\tif (total_size != 0) // Necessary here to prevent a pointer matching to an empty colony with one memory block retained with the skipfield wiped (see erase())\r\n\t\t{\r\n\t\t\t // Start with last group first, as will be the largest group in most cases:\r\n\t\t\tfor (group_pointer_type current_group = end_iterator.group_pointer; current_group != NULL; current_group = current_group->previous_group)\r\n\t\t\t{\r\n\t\t\t\tif (reinterpret_cast<aligned_pointer_type>(element_pointer) >= current_group->elements && reinterpret_cast<aligned_pointer_type>(element_pointer) < reinterpret_cast<aligned_pointer_type>(current_group->skipfield))\r\n\t\t\t\t{\r\n\t\t\t\t\tconst skipfield_pointer_type skipfield_pointer = current_group->skipfield + (reinterpret_cast<aligned_pointer_type>(element_pointer) - current_group->elements);\r\n\t\t\t\t\treturn (*skipfield_pointer == 0) ? iterator_type(current_group, reinterpret_cast<aligned_pointer_type>(element_pointer), skipfield_pointer) : static_cast<iterator_type>(end_iterator); // If element has been erased, return end()\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn end_iterator;\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\tinline iterator get_iterator(const pointer element_pointer) PLF_NOEXCEPT\r\n\t{\r\n\t\treturn get_it<false>(element_pointer);\r\n\t}\r\n\r\n\r\n\r\n\tinline const_iterator get_iterator(const const_pointer element_pointer) const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn get_it<true>(const_cast<pointer>(element_pointer));\r\n\t}\r\n\r\n\r\n\r\n\tinline allocator_type get_allocator() const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn *this;\r\n\t}\r\n\r\n\r\n\r\n\tvoid splice(colony &source)\r\n\t{\r\n\t\t// Process: if there are unused memory spaces at the end of the current back group of the chain, convert them\r\n\t\t// to skipped elements and add the locations to the group's free list.\r\n\t\t// Then link the destination's groups to the source's groups and nullify the source.\r\n\t\t// If the source has more unused memory spaces in the back group than the destination, swap them before processing to reduce the number of locations added to a free list and also subsequent jumps during iteration.\r\n\r\n\t\tassert(&source != this);\r\n\r\n\t\tif (source.total_size == 0)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\t\telse if (total_size == 0)\r\n\t\t{\r\n\t\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t\t*this = std::move(source);\r\n\t\t\t#else\r\n\t\t\t\tclear();\r\n\t\t\t\tswap(source);\r\n\t\t\t#endif\r\n\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// If there's more unused element locations in back memory block of destination than in back memory block of source, swap with source to reduce number of skipped elements during iteration, and reduce size of free-list:\r\n\t\tif ((reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer) > (reinterpret_cast<aligned_pointer_type>(source.end_iterator.group_pointer->skipfield) - source.end_iterator.element_pointer))\r\n\t\t{\r\n\t\t\tswap(source);\r\n\t\t}\r\n\r\n\r\n\t\t// Throw if incompatible group capacity found:\r\n\t\tif (source.tuple_allocator_pair.min_group_capacity < tuple_allocator_pair.min_group_capacity || source.group_allocator_pair.max_group_capacity > group_allocator_pair.max_group_capacity)\r\n\t\t{\r\n\t\t\tfor (group_pointer_type current_group = source.begin_iterator.group_pointer; current_group != NULL; current_group = current_group->next_group)\r\n\t\t\t{\r\n\t\t\t\tif (current_group->capacity < tuple_allocator_pair.min_group_capacity || current_group->capacity > group_allocator_pair.max_group_capacity)\r\n\t\t\t\t{\r\n\t\t\t\t\tthrow std::length_error(\"A source memory block capacity is outside of the destination's minimum or maximum memory block capacity limits - please change either the source or the destination's min/max block capacity limits using reshape() before calling splice() in this case\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\t// Add source list of groups-with-erasures to destination list of groups-with-erasures:\r\n\t\tif (source.groups_with_erasures_list_head != NULL)\r\n\t\t{\r\n\t\t\tif (groups_with_erasures_list_head != NULL)\r\n\t\t\t{\r\n\t\t\t\tgroup_pointer_type tail_group = groups_with_erasures_list_head;\r\n\r\n\t\t\t\twhile (tail_group->erasures_list_next_group != NULL)\r\n\t\t\t\t{\r\n\t\t\t\t\ttail_group = tail_group->erasures_list_next_group;\r\n\t\t\t\t}\r\n\r\n\t\t\t\ttail_group->erasures_list_next_group = source.groups_with_erasures_list_head;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tgroups_with_erasures_list_head = source.groups_with_erasures_list_head;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tconst skipfield_type distance_to_end = static_cast<skipfield_type>(reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield) - end_iterator.element_pointer);\r\n\r\n\t\tif (distance_to_end != 0) // 0 == edge case\r\n\t\t{\t // Mark unused element memory locations from back group as skipped/erased:\r\n\r\n\t\t\t// Update skipfield:\r\n\t\t\tconst skipfield_type previous_node_value = *(end_iterator.skipfield_pointer - 1);\r\n\t\t\tend_iterator.group_pointer->last_endpoint = reinterpret_cast<aligned_pointer_type>(end_iterator.group_pointer->skipfield);\r\n\r\n\t\t\tif (previous_node_value == 0) // no previous skipblock\r\n\t\t\t{\r\n\t\t\t\t*end_iterator.skipfield_pointer = distance_to_end;\r\n\t\t\t\t*(end_iterator.skipfield_pointer + distance_to_end - 1) = distance_to_end;\r\n\r\n\t\t\t\tconst skipfield_type index = static_cast<skipfield_type>(end_iterator.element_pointer - end_iterator.group_pointer->elements);\r\n\r\n\t\t\t\tif (end_iterator.group_pointer->free_list_head != std::numeric_limits<skipfield_type>::max()) // ie. if this group already has some erased elements\r\n\t\t\t\t{\r\n\t\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(end_iterator.group_pointer->elements + end_iterator.group_pointer->free_list_head) + 1) = index; // set prev free list head's 'next index' number to the index of the current element\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tend_iterator.group_pointer->erasures_list_next_group = groups_with_erasures_list_head; // add it to the groups-with-erasures free list\r\n\t\t\t\t\tgroups_with_erasures_list_head = end_iterator.group_pointer;\r\n\t\t\t\t}\r\n\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(end_iterator.element_pointer)) = end_iterator.group_pointer->free_list_head;\r\n\t\t\t\t*(reinterpret_cast<skipfield_pointer_type>(end_iterator.element_pointer) + 1) = std::numeric_limits<skipfield_type>::max();\r\n\t\t\t\tend_iterator.group_pointer->free_list_head = index;\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{ // update previous skipblock, no need to update free list:\r\n\t\t\t\t*(end_iterator.skipfield_pointer - previous_node_value) = *(end_iterator.skipfield_pointer + distance_to_end - 1) = static_cast<skipfield_type>(previous_node_value + distance_to_end);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\t// Update subsequent group numbers:\r\n\t\tgroup_pointer_type current_group = source.begin_iterator.group_pointer;\r\n\t\tsize_type current_group_number = end_iterator.group_pointer->group_number;\r\n\r\n\t\tdo\r\n\t\t{\r\n\t\t\tcurrent_group->group_number = ++current_group_number;\r\n\t\t\tcurrent_group = current_group->next_group;\r\n\t\t} while (current_group != NULL);\r\n\r\n\r\n\t\t// Join the destination and source group chains:\r\n\t\tend_iterator.group_pointer->next_group = source.begin_iterator.group_pointer;\r\n\t\tsource.begin_iterator.group_pointer->previous_group = end_iterator.group_pointer;\r\n\t\tend_iterator = source.end_iterator;\r\n\t\ttotal_size += source.total_size;\r\n\t\ttotal_capacity += source.total_capacity;\r\n\r\n\t\t// Remove source unused groups:\r\n\t\tsource.trim();\r\n\t\tsource.blank();\r\n\t}\r\n\r\n\r\n\r\nprivate:\r\n\r\n\tstruct less\r\n\t{\r\n\t\tbool operator() (const element_type &a, const element_type &b) const PLF_NOEXCEPT\r\n\t\t{\r\n\t\t\treturn a < b;\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\n\tstruct item_index_tuple\r\n\t{\r\n\t\tpointer original_location;\r\n\t\tsize_type original_index;\r\n\r\n\t\titem_index_tuple(const pointer _item, const size_type _index) PLF_NOEXCEPT:\r\n\t\t\toriginal_location(_item),\r\n\t\t\toriginal_index(_index)\r\n\t\t{}\r\n\t};\r\n\r\n\r\n\r\n\ttemplate <class comparison_function>\r\n\tstruct sort_dereferencer\r\n\t{\r\n\t\tcomparison_function stored_instance;\r\n\r\n\t\texplicit sort_dereferencer(const comparison_function &function_instance):\r\n\t\t\tstored_instance(function_instance)\r\n\t\t{}\r\n\r\n\t\tbool operator() (const item_index_tuple first, const item_index_tuple second)\r\n\t\t{\r\n\t\t\treturn stored_instance(*(first.original_location), *(second.original_location));\r\n\t\t}\r\n\t};\r\n\r\n\r\n\r\npublic:\r\n\r\n\r\n\ttemplate <class comparison_function>\r\n\tvoid sort(comparison_function compare)\r\n\t{\r\n\t\tif (total_size < 2)\r\n\t\t{\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\ttuple_pointer_type const sort_array = PLF_ALLOCATE(tuple_allocator_type, tuple_allocator_pair, total_size, NULL);\r\n\t\ttuple_pointer_type tuple_pointer = sort_array;\r\n\r\n\t\t// Construct pointers to all elements in the sequence:\r\n\t\tsize_type index = 0;\r\n\r\n\t\tfor (iterator current_element = begin_iterator; current_element != end_iterator; ++current_element, ++tuple_pointer, ++index)\r\n\t\t{\r\n\t\t\t#ifdef PLF_VARIADICS_SUPPORT\r\n\t\t\t\tPLF_CONSTRUCT(tuple_allocator_type, tuple_allocator_pair, tuple_pointer, &*current_element, index);\r\n\t\t\t#else\r\n\t\t\t\tPLF_CONSTRUCT(tuple_allocator_type, tuple_allocator_pair, tuple_pointer, item_index_tuple(&*current_element, index));\r\n\t\t\t#endif\r\n\t\t}\r\n\r\n\t\t// Now, sort the pointers by the values they point to (std::sort is default sort function if the macro below is not defined):\r\n\t\t#ifndef PLF_SORT_FUNCTION\r\n\t\t\tstd::sort(sort_array, sort_array + total_size, sort_dereferencer<comparison_function>(compare));\r\n\t\t#else\r\n\t\t\tPLF_SORT_FUNCTION(sort_array, sort_array + total_size, sort_dereferencer<comparison_function>(compare));\r\n\t\t#endif\r\n\r\n\t\t// Sort the actual elements via the tuple array:\r\n\t\tindex = 0;\r\n\r\n\t\tfor (tuple_pointer_type current_tuple = sort_array; current_tuple != tuple_pointer; ++current_tuple, ++index)\r\n\t\t{\r\n\t\t\tif (current_tuple->original_index != index)\r\n\t\t\t{\r\n\t\t\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t\t\telement_type end_value = std::move(*(current_tuple->original_location));\r\n\t\t\t\t#else\r\n\t\t\t\t\telement_type end_value = *(current_tuple->original_location);\r\n\t\t\t\t#endif\r\n\r\n\t\t\t\tsize_type destination_index = index;\r\n\t\t\t\tsize_type source_index = current_tuple->original_index;\r\n\r\n\t\t\t\tdo\r\n\t\t\t\t{\r\n\t\t\t\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t\t\t\t*(sort_array[destination_index].original_location) = std::move(*(sort_array[source_index].original_location));\r\n\t\t\t\t\t#else\r\n\t\t\t\t\t\t*(sort_array[destination_index].original_location) = *(sort_array[source_index].original_location);\r\n\t\t\t\t\t#endif\r\n\r\n\t\t\t\t\tdestination_index = source_index;\r\n\t\t\t\t\tsource_index = sort_array[destination_index].original_index;\r\n\t\t\t\t\tsort_array[destination_index].original_index = destination_index;\r\n\t\t\t\t} while (source_index != index);\r\n\r\n\t\t\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t\t\t*(sort_array[destination_index].original_location) = std::move(end_value);\r\n\t\t\t\t#else\r\n\t\t\t\t\t*(sort_array[destination_index].original_location) = end_value;\r\n\t\t\t\t#endif\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tPLF_DEALLOCATE(tuple_allocator_type, tuple_allocator_pair, sort_array, total_size);\r\n\t}\r\n\r\n\r\n\r\n\tinline void sort()\r\n\t{\r\n\t\tsort(less());\r\n\t}\r\n\r\n\r\n\r\n\tstruct colony_data : public uchar_allocator_type\r\n\t{\r\n\t\taligned_pointer_type * const block_pointers;\t\t\t\t// array of pointers to element memory blocks\r\n\t\tunsigned char * * const bitfield_pointers;\t\t\t\t// array of pointers to bitfields in the form of unsigned char arrays representing whether an element is erased or not (0 for erased).\r\n\t\tsize_t * const block_capacities;\t\t\t\t\t\t\t\t// array of the number of elements in each memory block\r\n\t\tconst size_t number_of_blocks;\t\t\t\t\t\t\t\t// size of each of the arrays above\r\n\r\n\r\n\t\tcolony_data(const size_type size) :\r\n\t\t\tblock_pointers(reinterpret_cast<aligned_pointer_type *>(PLF_ALLOCATE(uchar_allocator_type, *this, size * sizeof(aligned_pointer_type), NULL))),\r\n\t\t\tbitfield_pointers(reinterpret_cast<unsigned char **>(PLF_ALLOCATE(uchar_allocator_type, *this, size * sizeof(unsigned char *), NULL))),\r\n\t\t\tblock_capacities(reinterpret_cast<size_t *>(PLF_ALLOCATE(uchar_allocator_type, *this, size * sizeof(size_t), NULL))),\r\n\t\t\tnumber_of_blocks(size)\r\n\t\t{}\r\n\r\n\r\n\t\t~colony_data()\r\n\t\t{\r\n\t\t\tfor (size_t index = 0; index != number_of_blocks; ++index)\r\n\t\t\t{\r\n\t\t\t\tPLF_DEALLOCATE(uchar_allocator_type, *this, bitfield_pointers[index], (block_capacities[index] + 7) / 8);\r\n\t\t\t}\r\n\r\n\t\t\tPLF_DEALLOCATE(uchar_allocator_type, *this, reinterpret_cast<unsigned char *>(block_pointers), number_of_blocks * sizeof(aligned_pointer_type));\r\n\t\t\tPLF_DEALLOCATE(uchar_allocator_type, *this, reinterpret_cast<unsigned char *>(bitfield_pointers), number_of_blocks * sizeof(unsigned char *));\r\n\t\t\tPLF_DEALLOCATE(uchar_allocator_type, *this, reinterpret_cast<unsigned char *>(block_capacities), number_of_blocks * sizeof(size_t));\r\n\t\t}\r\n\t};\r\n\r\n\r\n\ttypedef colony_data hive_data;\r\n\r\n\r\n\r\nprivate:\r\n\r\n\tvoid setup_data_cell(colony_data *data, const group_pointer_type current_group, const size_t capacity, const size_t group_number)\r\n\t{\r\n\t\tconst size_t bitfield_capacity = (capacity + 7) / 8; // round up\r\n\r\n\t\tdata->block_pointers[group_number] = current_group->elements;\r\n\t\tunsigned char *bitfield_location = data->bitfield_pointers[group_number] = PLF_ALLOCATE(uchar_allocator_type, (*data), bitfield_capacity, NULL);\r\n\t\tdata->block_capacities[group_number] = capacity;\r\n\t\tstd::memset(bitfield_location, 0, bitfield_capacity);\r\n\r\n\t\tskipfield_pointer_type skipfield_pointer = current_group->skipfield;\r\n\t\tconst unsigned char *end = bitfield_location + bitfield_capacity;\r\n\r\n\t\tfor (size_t index = 0; bitfield_location != end; ++bitfield_location)\r\n\t\t{\r\n\t\t\tfor (unsigned char offset = 0; offset != 8 && index != capacity; ++index, ++offset, ++skipfield_pointer)\r\n\t\t\t{\r\n\t\t\t\t*bitfield_location |= static_cast<unsigned char>(static_cast<int>(!*skipfield_pointer) << offset);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n\r\npublic:\r\n\r\n\tcolony_data * data()\r\n\t{\r\n\t\tcolony_data *data = new colony_data(end_iterator.group_pointer->group_number + 1);\r\n\t\tsize_t group_number = 0;\r\n\r\n\t\tfor (group_pointer_type current_group = begin_iterator.group_pointer; current_group != end_iterator.group_pointer; current_group = current_group->next_group, ++group_number)\r\n\t\t{\r\n\t\t\tsetup_data_cell(data, current_group, current_group->capacity, group_number);\r\n\t\t}\r\n\r\n\t\t// Special case for end group:\r\n\t\tsetup_data_cell(data, end_iterator.group_pointer, static_cast<size_t>(end_iterator.group_pointer->last_endpoint - end_iterator.group_pointer->elements), group_number);\r\n\r\n\t\treturn data;\r\n\t}\r\n\r\n\r\n\r\n\r\n\tvoid swap(colony &source) PLF_NOEXCEPT_SWAP(allocator_type)\r\n\t{\r\n\t\tassert(&source != this);\r\n\r\n\t\t#ifdef PLF_TYPE_TRAITS_SUPPORT\r\n\t\t\tif PLF_CONSTEXPR (std::is_trivial<group_pointer_type>::value && std::is_trivial<aligned_pointer_type>::value && std::is_trivial<skipfield_pointer_type>::value) // if all pointer types are trivial we can just copy using memcpy - avoids constructors/destructors etc and is faster\r\n\t\t\t{\r\n\t\t\t\tchar temp[sizeof(colony)];\r\n\t\t\t\tstd::memcpy(&temp, static_cast<void *>(this), sizeof(colony));\r\n\t\t\t\tstd::memcpy(static_cast<void *>(this), static_cast<void *>(&source), sizeof(colony));\r\n\t\t\t\tstd::memcpy(static_cast<void *>(&source), &temp, sizeof(colony));\r\n\t\t\t}\r\n\t\t\t#ifdef PLF_MOVE_SEMANTICS_SUPPORT // Moving is probably going to be more efficient than copying, particularly if pointer types are non-trivial:\r\n\t\t\t\telse if PLF_CONSTEXPR (std::is_move_assignable<group_pointer_type>::value && std::is_move_assignable<aligned_pointer_type>::value && std::is_move_assignable<skipfield_pointer_type>::value && std::is_move_constructible<group_pointer_type>::value && std::is_move_constructible<aligned_pointer_type>::value && std::is_move_constructible<skipfield_pointer_type>::value)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony temp(std::move(source));\r\n\t\t\t\t\tsource = std::move(*this);\r\n\t\t\t\t\t*this = std::move(temp);\r\n\t\t\t\t}\r\n\t\t\t#endif\r\n\t\t\telse\r\n\t\t#endif\r\n\t\t{\r\n\t\t\tconst iterator\t\t\t\t\t\tswap_end_iterator = end_iterator, swap_begin_iterator = begin_iterator;\r\n\t\t\tconst group_pointer_type\t\tswap_groups_with_erasures_list_head = groups_with_erasures_list_head, swap_unused_groups_head = unused_groups_head;\r\n\t\t\tconst size_type\t\t\t\t\tswap_total_size = total_size, swap_total_capacity = total_capacity;\r\n\t\t\tconst skipfield_type \t\t\tswap_min_group_capacity = tuple_allocator_pair.min_group_capacity, swap_max_group_capacity = group_allocator_pair.max_group_capacity;\r\n\r\n\t\t\tend_iterator = source.end_iterator;\r\n\t\t\tbegin_iterator = source.begin_iterator;\r\n\t\t\tgroups_with_erasures_list_head = source.groups_with_erasures_list_head;\r\n\t\t\tunused_groups_head = source.unused_groups_head;\r\n\t\t\ttotal_size = source.total_size;\r\n\t\t\ttotal_capacity = source.total_capacity;\r\n\t\t\ttuple_allocator_pair.min_group_capacity = source.tuple_allocator_pair.min_group_capacity;\r\n\t\t\tgroup_allocator_pair.max_group_capacity = source.group_allocator_pair.max_group_capacity;\r\n\r\n\t\t\tsource.end_iterator = swap_end_iterator;\r\n\t\t\tsource.begin_iterator = swap_begin_iterator;\r\n\t\t\tsource.groups_with_erasures_list_head = swap_groups_with_erasures_list_head;\r\n\t\t\tsource.unused_groups_head = swap_unused_groups_head;\r\n\t\t\tsource.total_size = swap_total_size;\r\n\t\t\tsource.total_capacity = swap_total_capacity;\r\n\t\t\tsource.tuple_allocator_pair.min_group_capacity = swap_min_group_capacity;\r\n\t\t\tsource.group_allocator_pair.max_group_capacity = swap_max_group_capacity;\r\n\t\t}\r\n\t}\r\n\r\n};\t// colony\r\n\r\n\r\n\r\n// Set up hive as alias of colony:\r\n#if defined(__cplusplus) && __cplusplus >= 201103L\r\n\ttypedef colony_limits hive_limits;\r\n\ttypedef colony_priority hive_priority;\r\n\r\n\ttemplate <class element_type, class allocator_type = std::allocator<element_type>, plf::hive_priority priority = plf::performance>\r\n\tusing hive = plf::colony<element_type, allocator_type, priority>;\r\n#endif\r\n\r\n\r\n\r\n// Used by std::erase_if() overload below:\r\ntemplate<class element_type>\r\nstruct colony_eq_to\r\n{\r\n\tconst element_type value;\r\n\r\n\texplicit colony_eq_to(const element_type store_value): /* may not be noexcept as the element may allocate and therefore potentially throw when copied */\r\n\t\tvalue(store_value)\r\n\t{}\r\n\r\n\tinline bool operator() (const element_type compare_value) const PLF_NOEXCEPT\r\n\t{\r\n\t\treturn value == compare_value;\r\n\t}\r\n};\r\n\r\n\r\n} // plf namespace\r\n\r\n\r\n\r\n\r\nnamespace std\r\n{\r\n\r\n\ttemplate <class element_type, class allocator_type, plf::colony_priority priority>\r\n\tinline void swap (plf::colony<element_type, allocator_type, priority> &a, plf::colony<element_type, allocator_type, priority> &b) PLF_NOEXCEPT_SWAP(allocator_type)\r\n\t{\r\n\t\ta.swap(b);\r\n\t}\r\n\r\n\r\n\r\n\ttemplate <class element_type, class allocator_type, plf::colony_priority priority, class predicate_function>\r\n\ttypename plf::colony<element_type, allocator_type, priority>::size_type erase_if(plf::colony<element_type, allocator_type, priority> &container, predicate_function predicate)\r\n\t{\r\n\t\ttypedef typename plf::colony<element_type, allocator_type, priority> colony;\r\n\t\ttypedef typename colony::const_iterator \tconst_iterator;\r\n\t\ttypedef typename colony::size_type \t\t\tsize_type;\r\n\t\tsize_type count = 0;\r\n\r\n\t\tfor(const_iterator current = container.begin(), end = container.end(); current != end;)\r\n\t\t{\r\n\t\t\tif (predicate(*current))\r\n\t\t\t{\r\n\t\t\t\tconst size_type original_count = ++count;\r\n\t\t\t\tconst_iterator last(++const_iterator(current));\r\n\r\n\t\t\t\twhile(last != end && predicate(*last))\r\n\t\t\t\t{\r\n\t\t\t\t\t++last;\r\n\t\t\t\t\t++count;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (count != original_count)\r\n\t\t\t\t{\r\n\t\t\t\t\tcurrent = container.erase(current, last);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\tcurrent = container.erase(current);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tend = container.end();\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\t++current;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn count;\r\n\t}\r\n\r\n\r\n\r\n\ttemplate <class element_type, class allocator_type, plf::colony_priority priority>\r\n\tinline typename plf::colony<element_type, allocator_type, priority>::size_type erase(plf::colony<element_type, allocator_type, priority> &container, const element_type &value)\r\n\t{\r\n\t\treturn erase_if(container, plf::colony_eq_to<element_type>(value));\r\n\t}\r\n}\r\n\r\n\r\n#undef PLF_MIN_BLOCK_CAPACITY\r\n#undef PLF_GROUP_ALIGNED_BLOCK_SIZE\r\n\r\n#undef PLF_FORCE_INLINE\r\n#undef PLF_ALIGNMENT_SUPPORT\r\n#undef PLF_INITIALIZER_LIST_SUPPORT\r\n#undef PLF_TYPE_TRAITS_SUPPORT\r\n#undef PLF_ALLOCATOR_TRAITS_SUPPORT\r\n#undef PLF_VARIADICS_SUPPORT\r\n#undef PLF_MOVE_SEMANTICS_SUPPORT\r\n#undef PLF_NOEXCEPT\r\n#undef PLF_NOEXCEPT_SWAP\r\n#undef PLF_NOEXCEPT_MOVE_ASSIGN\r\n#undef PLF_CONSTEXPR\r\n#undef PLF_CPP20_SUPPORT\r\n#undef PLF_STATIC_ASSERT\r\n\r\n#undef PLF_CONSTRUCT\r\n#undef PLF_DESTROY\r\n#undef PLF_ALLOCATE\r\n#undef PLF_DEALLOCATE\r\n\r\n#endif // PLF_COLONY_H\r\n"
  },
  {
    "path": "SG14/ring.h",
    "content": "#pragma once\n\n#include <cstddef>\n#include <type_traits>\n#include <iterator>\n#include <cassert>\n\nnamespace sg14\n{\n\ttemplate <typename T>\n\tstruct null_popper\n\t{\n\t\tvoid operator()(T&) const noexcept;\n\t};\n\n\ttemplate <typename T>\n\tstruct default_popper\n\t{\n\t\tT operator()(T& t) const;\n\t};\n\n\ttemplate <typename T>\n\tstruct copy_popper\n\t{\n\t\tcopy_popper(T t);\n\t\tT operator()(T& t) const;\n\tprivate:\n\t\tT m_copy;\n\t};\n\n\ttemplate <typename, bool>\n\tclass ring_iterator;\n\n\ttemplate<typename T, class Popper = default_popper<T>>\n\tclass ring_span\n\t{\n\tpublic:\n\t\tusing type = ring_span<T, Popper>;\n\t\tusing size_type = std::size_t;\n\t\tusing value_type = T;\n\t\tusing pointer = T*;\n\t\tusing reference = T&;\n\t\tusing const_reference = const T&;\n\t\tusing iterator = ring_iterator<type, false>;\n\t\tusing const_iterator = ring_iterator<type, true>;\n\t\tusing reverse_iterator = std::reverse_iterator<iterator>;\n\t\tusing const_reverse_iterator = std::reverse_iterator<const_iterator>;\n\n\t\tfriend class ring_iterator<type, false>;\n\t\tfriend class ring_iterator<type, true>;\n\n\t\ttemplate <class ContiguousIterator>\n\t\tring_span(ContiguousIterator begin, ContiguousIterator end, Popper p = Popper()) noexcept;\n\n\t\ttemplate <class ContiguousIterator>\n\t\tring_span(ContiguousIterator begin, ContiguousIterator end, ContiguousIterator first, size_type size, Popper p = Popper()) noexcept;\n\n\t\tring_span(ring_span&&) = default;\n\t\tring_span& operator=(ring_span&&) = default;\n\n\t\tbool empty() const noexcept;\n\t\tbool full() const noexcept;\n\t\tsize_type size() const noexcept;\n\t\tsize_type capacity() const noexcept;\n\n\t\treference front() noexcept;\n\t\tconst_reference front() const noexcept;\n\t\treference back() noexcept;\n\t\tconst_reference back() const noexcept;\n\n\t\titerator begin() noexcept;\n\t\tconst_iterator begin() const noexcept;\n\t\titerator end() noexcept;\n\t\tconst_iterator end() const noexcept;\n\n\t\tconst_iterator cbegin() const noexcept;\n\t\tconst_reverse_iterator crbegin() const noexcept;\n\t\treverse_iterator rbegin() noexcept;\n\t\tconst_reverse_iterator rbegin() const noexcept;\n\t\tconst_iterator cend() const noexcept;\n\t\tconst_reverse_iterator crend() const noexcept;\n\t\treverse_iterator rend() noexcept;\n\t\tconst_reverse_iterator rend() const noexcept;\n\n\t\ttemplate<bool b = true, typename = std::enable_if_t<b && std::is_copy_assignable<T>::value>>\n\t\tvoid push_back(const value_type& from_value) noexcept(std::is_nothrow_copy_assignable<T>::value);\n\t\ttemplate<bool b = true, typename = std::enable_if_t<b && std::is_move_assignable<T>::value>>\n\t\tvoid push_back(value_type&& from_value) noexcept(std::is_nothrow_move_assignable<T>::value);\n\t\ttemplate<class... FromType>\n\t\tvoid emplace_back(FromType&&... from_value) noexcept(std::is_nothrow_constructible<T, FromType...>::value && std::is_nothrow_move_assignable<T>::value);\n\t\tauto pop_front();\n\n\t\tvoid swap(type& rhs) noexcept;// (std::is_nothrow_swappable<Popper>::value);\n\n\t\t// Example implementation\n\tprivate:\n\t\treference at(size_type idx) noexcept;\n\t\tconst_reference at(size_type idx) const noexcept;\n\t\tsize_type back_idx() const noexcept;\n\t\tvoid increase_size() noexcept;\n\n\t\tT* m_data;\n\t\tsize_type m_size;\n\t\tsize_type m_capacity;\n\t\tsize_type m_front_idx;\n\t\tPopper m_popper;\n\t};\n\n\ttemplate<typename T, class Popper>\n\tvoid swap(ring_span<T, Popper>&, ring_span<T, Popper>&) noexcept;\n\n\ttemplate <typename Ring, bool is_const>\n\tclass ring_iterator\n\t{\n\tpublic:\n\t\tusing type = ring_iterator<Ring, is_const>;\n\t\tusing value_type = typename Ring::value_type;\n\t\tusing difference_type = std::ptrdiff_t;\n\t\tusing pointer = typename std::conditional_t<is_const, const value_type, value_type>*;\n\t\tusing reference = typename std::conditional_t<is_const, const value_type, value_type>&;\n\t\tusing iterator_category = std::random_access_iterator_tag;\n\n\t\toperator ring_iterator<Ring, true>() const noexcept;\n\n\t\ttemplate <bool C>\n\t\tbool operator==(const ring_iterator<Ring, C>& rhs) const noexcept;\n\t\ttemplate <bool C>\n\t\tbool operator!=(const ring_iterator<Ring, C>& rhs) const noexcept;\n\t\ttemplate <bool C>\n\t\tbool operator<(const ring_iterator<Ring, C>& rhs) const noexcept;\n\t\ttemplate <bool C>\n\t\tbool operator<=(const ring_iterator<Ring, C>& rhs) const noexcept;\n\t\ttemplate <bool C>\n\t\tbool operator>(const ring_iterator<Ring, C>& rhs) const noexcept;\n\t\ttemplate <bool C>\n\t\tbool operator>=(const ring_iterator<Ring, C>& rhs) const noexcept;\n\n\t\treference operator*() const noexcept;\n\t\ttype& operator++() noexcept;\n\t\ttype operator++(int) noexcept;\n\t\ttype& operator--() noexcept;\n\t\ttype operator--(int) noexcept;\n\n\t\ttype& operator+=(std::ptrdiff_t i) noexcept;\n\t\ttype& operator-=(std::ptrdiff_t i) noexcept;\n\n\t\ttemplate<bool C>\n\t\tstd::ptrdiff_t operator-(const ring_iterator<Ring, C>& rhs) const noexcept;\n\n\t\t// Example implementation\n\tprivate:\n\t\tfriend Ring;\n\t\tfriend class ring_iterator<Ring, !is_const>;\n\t\tusing size_type = typename Ring::size_type;\n\t\tring_iterator(size_type idx, std::conditional_t<is_const, const Ring, Ring>* rv) noexcept;\n\t\tsize_type m_idx;\n\t\tstd::conditional_t<is_const, const Ring, Ring>* m_rv;\n\t};\n\n\ttemplate <typename Ring, bool C>\n\tring_iterator<Ring, C> operator+(ring_iterator<Ring, C> it, std::ptrdiff_t) noexcept;\n\n\ttemplate <typename Ring, bool C>\n\tring_iterator<Ring, C> operator-(ring_iterator<Ring, C> it, std::ptrdiff_t) noexcept;\n} // namespace sg14\n\n// Sample implementation\n\ntemplate <typename T>\nvoid sg14::null_popper<T>::operator()(T&) const noexcept\n{}\n\ntemplate <typename T>\nT sg14::default_popper<T>::operator()(T& t) const\n{\n\treturn std::move(t);\n}\n\ntemplate <typename T>\nsg14::copy_popper<T>::copy_popper(T t)\n\t: m_copy(std::move(t))\n{}\n\ntemplate <typename T>\nT sg14::copy_popper<T>::operator()(T& t) const\n{\n\tT old = m_copy;\n\tusing std::swap;\n\tswap(old, t);\n\treturn old;\n}\n\ntemplate<typename T, class Popper>\ntemplate<class ContiguousIterator>\nsg14::ring_span<T, Popper>::ring_span(ContiguousIterator begin, ContiguousIterator end, Popper p) noexcept\n\t: m_data(&*begin)\n\t, m_size(0)\n\t, m_capacity(end - begin)\n\t, m_front_idx(0)\n\t, m_popper(std::move(p))\n{}\n\ntemplate<typename T, class Popper>\ntemplate<class ContiguousIterator>\nsg14::ring_span<T, Popper>::ring_span(ContiguousIterator begin, ContiguousIterator end, ContiguousIterator first, size_type size, Popper p) noexcept\n\t: m_data(&*begin)\n\t, m_size(size)\n\t, m_capacity(end - begin)\n\t, m_front_idx(first - begin)\n\t, m_popper(std::move(p))\n{}\n\ntemplate<typename T, class Popper>\nbool sg14::ring_span<T, Popper>::empty() const noexcept\n{\n\treturn m_size == 0;\n}\n\ntemplate<typename T, class Popper>\nbool sg14::ring_span<T, Popper>::full() const noexcept\n{\n\treturn m_size == m_capacity;\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::size_type sg14::ring_span<T, Popper>::size() const noexcept\n{\n\treturn m_size;\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::size_type sg14::ring_span<T, Popper>::capacity() const noexcept\n{\n\treturn m_capacity;\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::reference sg14::ring_span<T, Popper>::front() noexcept\n{\n\treturn *begin();\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::reference sg14::ring_span<T, Popper>::back() noexcept\n{\n\treturn *(--end());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reference sg14::ring_span<T, Popper>::front() const noexcept\n{\n\treturn *begin();\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reference sg14::ring_span<T, Popper>::back() const noexcept\n{\n\treturn *(--end());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::iterator sg14::ring_span<T, Popper>::begin() noexcept\n{\n\treturn iterator(m_front_idx, this);\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_iterator sg14::ring_span<T, Popper>::begin() const noexcept\n{\n\treturn const_iterator(m_front_idx, this);\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::iterator sg14::ring_span<T, Popper>::end() noexcept\n{\n\treturn iterator(size() + m_front_idx, this);\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_iterator sg14::ring_span<T, Popper>::end() const noexcept\n{\n\treturn const_iterator(size() + m_front_idx, this);\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_iterator sg14::ring_span<T, Popper>::cbegin() const noexcept\n{\n\treturn begin();\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::reverse_iterator sg14::ring_span<T, Popper>::rbegin() noexcept\n{\n\treturn reverse_iterator(end());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reverse_iterator sg14::ring_span<T, Popper>::rbegin() const noexcept\n{\n\treturn const_reverse_iterator(end());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reverse_iterator sg14::ring_span<T, Popper>::crbegin() const noexcept\n{\n\treturn const_reverse_iterator(end());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_iterator sg14::ring_span<T, Popper>::cend() const noexcept\n{\n\treturn end();\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::reverse_iterator sg14::ring_span<T, Popper>::rend() noexcept\n{\n\treturn reverse_iterator(begin());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reverse_iterator sg14::ring_span<T, Popper>::rend() const noexcept\n{\n\treturn const_reverse_iterator(begin());\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reverse_iterator sg14::ring_span<T, Popper>::crend() const noexcept\n{\n\treturn const_reverse_iterator(begin());\n}\n\ntemplate<typename T, class Popper>\ntemplate<bool b, typename>\nvoid sg14::ring_span<T, Popper>::push_back(const T& value) noexcept(std::is_nothrow_copy_assignable<T>::value)\n{\n\tm_data[back_idx()] = value;\n\tincrease_size();\n}\n\ntemplate<typename T, class Popper>\ntemplate<bool b, typename>\nvoid sg14::ring_span<T, Popper>::push_back(T&& value) noexcept(std::is_nothrow_move_assignable<T>::value)\n{\n\tm_data[back_idx()] = std::move(value);\n\tincrease_size();\n}\n\ntemplate<typename T, class Popper>\ntemplate<class... FromType>\nvoid sg14::ring_span<T, Popper>::emplace_back(FromType&&... from_value) noexcept(std::is_nothrow_constructible<T, FromType...>::value && std::is_nothrow_move_assignable<T>::value)\n{\n\tm_data[back_idx()] = T(std::forward<FromType>(from_value)...);\n\tincrease_size();\n}\n\ntemplate<typename T, class Popper>\nauto sg14::ring_span<T, Popper>::pop_front()\n{\n\tassert(m_size != 0);\n\tauto old_front_idx = m_front_idx;\n\tm_front_idx = (m_front_idx + 1) % m_capacity;\n\t--m_size;\n\treturn m_popper(m_data[old_front_idx]);\n}\n\ntemplate<typename T, class Popper>\nvoid sg14::ring_span<T, Popper>::swap(sg14::ring_span<T, Popper>& rhs) noexcept//(std::is_nothrow_swappable<Popper>::value)\n{\n\tusing std::swap;\n\tswap(m_data, rhs.m_data);\n\tswap(m_size, rhs.m_size);\n\tswap(m_capacity, rhs.m_capacity);\n\tswap(m_front_idx, rhs.m_front_idx);\n\tswap(m_popper, rhs.m_popper);\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::reference sg14::ring_span<T, Popper>::at(size_type i) noexcept\n{\n\treturn m_data[i % m_capacity];\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::const_reference sg14::ring_span<T, Popper>::at(size_type i) const noexcept\n{\n\treturn m_data[i % m_capacity];\n}\n\ntemplate<typename T, class Popper>\ntypename sg14::ring_span<T, Popper>::size_type sg14::ring_span<T, Popper>::back_idx() const noexcept\n{\n\treturn (m_front_idx + m_size) % m_capacity;\n}\n\ntemplate<typename T, class Popper>\nvoid sg14::ring_span<T, Popper>::increase_size() noexcept\n{\n\tif (++m_size > m_capacity)\n\t{\n\t\tm_size = m_capacity;\n\t\tm_front_idx = (m_front_idx + 1) % m_capacity;\n\t}\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>::operator sg14::ring_iterator<Ring, true>() const noexcept\n{\n\treturn sg14::ring_iterator<Ring, true>(m_idx, m_rv);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator==(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn (m_idx == rhs.m_idx) && (m_rv == rhs.m_rv);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator!=(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn !(*this == rhs);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator<(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn (m_idx < rhs.m_idx) && (m_rv == rhs.m_rv);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator<=(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn !(rhs < *this);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator>(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn (rhs < *this);\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nbool sg14::ring_iterator<Ring, is_const>::operator>=(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn !(*this < rhs);\n}\n\ntemplate <typename Ring, bool is_const>\ntypename sg14::ring_iterator<Ring, is_const>::reference sg14::ring_iterator<Ring, is_const>::operator*() const noexcept\n{\n\treturn m_rv->at(m_idx);\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>& sg14::ring_iterator<Ring, is_const>::operator++() noexcept\n{\n\t++m_idx;\n\treturn *this;\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const> sg14::ring_iterator<Ring, is_const>::operator++(int) noexcept\n{\n\tauto r(*this);\n\t++*this;\n\treturn r;\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>& sg14::ring_iterator<Ring, is_const>::operator--() noexcept\n{\n\t--m_idx;\n\treturn *this;\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const> sg14::ring_iterator<Ring, is_const>::operator--(int) noexcept\n{\n\tauto r(*this);\n\t--*this;\n\treturn r;\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>& sg14::ring_iterator<Ring, is_const>::operator+=(std::ptrdiff_t i) noexcept\n{\n\tthis->m_idx += i;\n\treturn *this;\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>& sg14::ring_iterator<Ring, is_const>::operator-=(std::ptrdiff_t i) noexcept\n{\n\tthis->m_idx -= i;\n\treturn *this;\n}\n\ntemplate <typename Ring, bool is_const>\ntemplate<bool C>\nstd::ptrdiff_t sg14::ring_iterator<Ring, is_const>::operator-(const sg14::ring_iterator<Ring, C>& rhs) const noexcept\n{\n\treturn static_cast<std::ptrdiff_t>(this->m_idx) - static_cast<std::ptrdiff_t>(rhs.m_idx);\n}\n\ntemplate <typename Ring, bool is_const>\nsg14::ring_iterator<Ring, is_const>::ring_iterator(typename sg14::ring_iterator<Ring, is_const>::size_type idx, std::conditional_t<is_const, const Ring, Ring>* rv) noexcept\n\t: m_idx(idx)\n\t, m_rv(rv)\n{}\n\n\nnamespace sg14\n{\n\ttemplate<typename T, class Popper>\n\tvoid swap(ring_span<T, Popper>& a, ring_span<T, Popper>& b) noexcept\n\t{\n\t\ta.swap(b);\n\t}\n\n\ttemplate <typename Ring, bool C>\n\tring_iterator<Ring, C> operator+(ring_iterator<Ring, C> it, std::ptrdiff_t i) noexcept\n\t{\n\t\tit += i;\n\t\treturn it;\n\t}\n\n\ttemplate <typename Ring, bool C>\n\tring_iterator<Ring, C> operator-(ring_iterator<Ring, C> it, std::ptrdiff_t i) noexcept\n\t{\n\t\tit -= i;\n\t\treturn it;\n\t}\n} // namespace sg14\n"
  },
  {
    "path": "SG14/slot_map.h",
    "content": "/*\n * Boost Software License - Version 1.0 - August 17th, 2003\n *\n * Permission is hereby granted, free of charge, to any person or organization\n * obtaining a copy of the software and accompanying documentation covered by\n * this license (the \"Software\") to use, reproduce, display, distribute,\n * execute, and transmit the Software, and to prepare derivative works of the\n * Software, and to permit third-parties to whom the Software is furnished to\n * do so, all subject to the following:\n *\n * The copyright notices in the Software and this entire statement, including\n * the above license grant, this restriction and the following disclaimer,\n * must be included in all copies of the Software, in whole or in part, and\n * all derivative works of the Software, unless such copies or derivative\n * works are solely in the form of machine-executable object code generated by\n * a source language processor.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT\n * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE\n * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n */\n\n#pragma once\n\n#include <type_traits>\n#include <utility>\n#include <vector>\n\n#ifndef SLOT_MAP_THROW_EXCEPTION\n#include <stdexcept>\n#define SLOT_MAP_THROW_EXCEPTION(type, ...) throw type(__VA_ARGS__)\n#endif\n\nnamespace stdext {\n\nnamespace slot_map_detail {\n\ntemplate<size_t I> struct priority_tag : public priority_tag<I-1> {};\ntemplate<> struct priority_tag<0> {};\n\ntemplate<class Ctr, class SizeType>\ninline auto reserve_if_possible(Ctr&, SizeType, priority_tag<0>) -> void {}\n\ntemplate<class Ctr, class SizeType>\ninline auto reserve_if_possible(Ctr& ctr, SizeType n, priority_tag<1>) -> decltype(void(ctr.reserve(n)))\n{\n    ctr.reserve(n);\n}\n\ntemplate<class Ctr, class SizeType>\ninline void reserve_if_possible(Ctr& ctr, const SizeType& n)\n{\n    slot_map_detail::reserve_if_possible(ctr, n, priority_tag<1>{});\n}\n\n} // namespace slot_map_detail\n\ntemplate<\n    class T,\n    class Key = std::pair<unsigned, unsigned>,\n    template<class...> class Container = std::vector\n>\nclass slot_map\n{\n#if __cplusplus >= 201703L\n    static constexpr auto get_index(const Key& k) { const auto& [idx, gen] = k; return idx; }\n    static constexpr auto get_generation(const Key& k) { const auto& [idx, gen] = k; return gen; }\n    template<class Integral> static constexpr void set_index(Key& k, Integral value) { auto& [idx, gen] = k; idx = static_cast<key_index_type>(value); }\n    static constexpr void increment_generation(Key& k) { auto& [idx, gen] = k; ++gen; }\n#else\n    static constexpr auto get_index(const Key& k) { using std::get; return get<0>(k); }\n    static constexpr auto get_generation(const Key& k) { using std::get; return get<1>(k); }\n    template<class Integral> static constexpr void set_index(Key& k, Integral value) { using std::get; get<0>(k) = static_cast<key_index_type>(value); }\n    static constexpr void increment_generation(Key& k) { using std::get; ++get<1>(k); }\n#endif\n\n    using slot_iterator = typename Container<Key>::iterator;\n\npublic:\n    using key_type = Key;\n    using mapped_type = T;\n\n    using key_index_type = decltype(slot_map::get_index(std::declval<Key>()));\n    using key_generation_type = decltype(slot_map::get_generation(std::declval<Key>()));\n\n    using container_type = Container<mapped_type>;\n    using reference = typename container_type::reference;\n    using const_reference = typename container_type::const_reference;\n    using pointer = typename container_type::pointer;\n    using const_pointer = typename container_type::const_pointer;\n    using iterator = typename container_type::iterator;\n    using const_iterator = typename container_type::const_iterator;\n    using reverse_iterator = typename container_type::reverse_iterator;\n    using const_reverse_iterator = typename container_type::const_reverse_iterator;\n\n    using size_type = typename container_type::size_type;\n    using value_type = typename container_type::value_type;\n\n    static_assert(std::is_same<value_type, mapped_type>::value, \"Container<T>::value_type must be identical to T\");\n\n    constexpr slot_map() = default;\n    constexpr slot_map(const slot_map&) = default;\n    constexpr slot_map(slot_map&&) = default;\n    constexpr slot_map& operator=(const slot_map&) = default;\n    constexpr slot_map& operator=(slot_map&&) = default;\n    ~slot_map() = default;\n\n    // The at() functions have both generation counter checking\n    // and bounds checking, and throw if either check fails.\n    // O(1) time and space complexity.\n    //\n    constexpr reference at(const key_type& key) {\n        auto value_iter = this->find(key);\n        if (value_iter == this->end()) {\n            SLOT_MAP_THROW_EXCEPTION(std::out_of_range, \"at\");\n        }\n        return *value_iter;\n    }\n    constexpr const_reference at(const key_type& key) const {\n        auto value_iter = this->find(key);\n        if (value_iter == this->end()) {\n            SLOT_MAP_THROW_EXCEPTION(std::out_of_range, \"at\");\n        }\n        return *value_iter;\n    }\n\n    // The bracket operator[] has a generation counter check.\n    // If the check fails it is undefined behavior.\n    // O(1) time and space complexity.\n    //\n    constexpr reference operator[](const key_type& key)              { return *find_unchecked(key); }\n    constexpr const_reference operator[](const key_type& key) const  { return *find_unchecked(key); }\n\n    // The find() functions have generation counter checking.\n    // If the check fails, the result of end() is returned.\n    // O(1) time and space complexity.\n    //\n    constexpr iterator find(const key_type& key) {\n        auto slot_index = get_index(key);\n        if (slot_index >= slots_.size()) {\n            return end();\n        }\n        auto slot_iter = std::next(slots_.begin(), slot_index);\n        if (get_generation(*slot_iter) != get_generation(key)) {\n            return end();\n        }\n        auto value_iter = std::next(values_.begin(), get_index(*slot_iter));\n        return value_iter;\n    }\n    constexpr const_iterator find(const key_type& key) const {\n        auto slot_index = get_index(key);\n        if (slot_index >= slots_.size()) {\n            return end();\n        }\n        auto slot_iter = std::next(slots_.begin(), slot_index);\n        if (get_generation(*slot_iter) != get_generation(key)) {\n            return end();\n        }\n        auto value_iter = std::next(values_.begin(), get_index(*slot_iter));\n        return value_iter;\n    }\n\n    // The find_unchecked() functions perform no checks of any kind.\n    // O(1) time and space complexity.\n    //\n    constexpr iterator find_unchecked(const key_type& key) {\n        auto slot_iter = std::next(slots_.begin(), get_index(key));\n        auto value_iter = std::next(values_.begin(), get_index(*slot_iter));\n        return value_iter;\n    }\n    constexpr const_iterator find_unchecked(const key_type& key) const {\n        auto slot_iter = std::next(slots_.begin(), get_index(key));\n        auto value_iter = std::next(values_.begin(), get_index(*slot_iter));\n        return value_iter;\n    }\n\n    // All begin() and end() variations have O(1) time and space complexity.\n    //\n    constexpr iterator begin()                         { return values_.begin(); }\n    constexpr iterator end()                           { return values_.end(); }\n    constexpr const_iterator begin() const             { return values_.begin(); }\n    constexpr const_iterator end() const               { return values_.end(); }\n    constexpr const_iterator cbegin() const            { return values_.begin(); }\n    constexpr const_iterator cend() const              { return values_.end(); }\n    constexpr reverse_iterator rbegin()                { return values_.rbegin(); }\n    constexpr reverse_iterator rend()                  { return values_.rend(); }\n    constexpr const_reverse_iterator rbegin() const    { return values_.rbegin(); }\n    constexpr const_reverse_iterator rend() const      { return values_.rend(); }\n    constexpr const_reverse_iterator crbegin() const   { return values_.rbegin(); }\n    constexpr const_reverse_iterator crend() const     { return values_.rend(); }\n\n    // Functions for checking the size and capacity of the adapted container\n    // have the same complexity as the adapted container.\n    // reserve(n) has the complexity of the adapted container, and uses\n    // additional time which is linear on the increase in size.\n    // This is caused by adding the new slots to the free list.\n    //\n    constexpr bool empty() const                      { return values_.size() == 0; }\n    constexpr size_type size() const                  { return values_.size(); }\n    // constexpr size_type max_size() const; TODO, NO SEMANTICS\n\n    constexpr void reserve(size_type n) {\n        slot_map_detail::reserve_if_possible(values_, n);\n        slot_map_detail::reserve_if_possible(reverse_map_, n);\n        reserve_slots(n);\n    }\n\n    template<class C = Container<T>, class = decltype(std::declval<const C&>().capacity())>\n    constexpr size_type capacity() const {\n        return values_.capacity();\n    }\n\n    // Functions for accessing and modifying the size of the slots container.\n    // These are beneficial as allocating more slots than values will cause the\n    // generation counter increases to be more evenly distributed across the slots.\n    //\n    constexpr void reserve_slots(size_type n) {\n        slot_map_detail::reserve_if_possible(slots_, n);\n        key_index_type original_num_slots = static_cast<key_index_type>(slots_.size());\n        if (original_num_slots < n) {\n            slots_.emplace_back(key_type{next_available_slot_index_, key_generation_type{}});\n            key_index_type last_new_slot = original_num_slots;\n            --n;\n            while (last_new_slot != n) {\n                slots_.emplace_back(key_type{last_new_slot, key_generation_type{}});\n                ++last_new_slot;\n            }\n            next_available_slot_index_ = last_new_slot;\n        }\n    }\n    constexpr size_type slot_count() const { return slots_.size(); }\n\n    // These operations have O(1) time and space complexity.\n    // When size() == capacity() an allocation is required\n    // which has O(n) time and space complexity.\n    //\n    constexpr key_type insert(const mapped_type& value)   { return this->emplace(value); }\n    constexpr key_type insert(mapped_type&& value)        { return this->emplace(std::move(value)); }\n\n    template<class... Args> constexpr key_type emplace(Args&&... args) {\n        auto value_pos = values_.size();\n        values_.emplace_back(std::forward<Args>(args)...);\n        reverse_map_.emplace_back(next_available_slot_index_);\n        if (next_available_slot_index_ == slots_.size()) {\n            auto idx = next_available_slot_index_; ++idx;\n            slots_.emplace_back(key_type{idx, key_generation_type{}});  // make a new slot\n            last_available_slot_index_ = idx;\n        }\n        auto slot_iter = std::next(slots_.begin(), next_available_slot_index_);\n        if (next_available_slot_index_ == last_available_slot_index_) {\n            next_available_slot_index_ = static_cast<key_index_type>(slots_.size());\n            last_available_slot_index_ = next_available_slot_index_;\n        } else {\n            next_available_slot_index_ = this->get_index(*slot_iter);\n        }\n        this->set_index(*slot_iter, value_pos);\n        key_type result = *slot_iter;\n        this->set_index(result, std::distance(slots_.begin(), slot_iter));\n        return result;\n    }\n\n    // Each erase() version has an O(1) time complexity per value\n    // and O(1) space complexity.\n    //\n    constexpr iterator erase(iterator pos) { return this->erase(const_iterator(pos)); }\n    constexpr iterator erase(iterator first, iterator last) { return this->erase(const_iterator(first), const_iterator(last)); }\n    constexpr iterator erase(const_iterator pos) {\n        auto slot_iter = this->slot_iter_from_value_iter(pos);\n        return erase_slot_iter(slot_iter);\n    }\n    constexpr iterator erase(const_iterator first, const_iterator last) {\n        // Must use indexes, not iterators, because Container iterators might be invalidated by pop_back\n        auto first_index = std::distance(this->cbegin(), first);\n        auto last_index = std::distance(this->cbegin(), last);\n        while (last_index != first_index) {\n            --last_index;\n            auto iter = std::next(this->cbegin(), last_index);\n            this->erase(iter);\n        }\n        return std::next(this->begin(), first_index);\n    }\n    constexpr size_type erase(const key_type& key) {\n        auto iter = this->find(key);\n        if (iter == this->end()) {\n            return 0;\n        }\n        this->erase(iter);\n        return 1;\n    }\n\n    // clear() has O(n) time complexity and O(1) space complexity.\n    // It also has semantics differing from erase(begin(), end())\n    // in that it also resets the generation counter of every slot\n    // and rebuilds the free list.\n    //\n    constexpr void clear() {\n        // This resets the generation counters, which \"undefined-behavior-izes\" at() and find() for the old keys.\n        slots_.clear();\n        values_.clear();\n        reverse_map_.clear();\n        next_available_slot_index_ = key_index_type{};\n        last_available_slot_index_ = key_index_type{};\n    }\n\n    // swap is not mentioned in P0661r1 but it should be.\n    constexpr void swap(slot_map& rhs) {\n        using std::swap;\n        swap(slots_, rhs.slots_);\n        swap(values_, rhs.values_);\n        swap(reverse_map_, rhs.reverse_map_);\n        swap(next_available_slot_index_, rhs.next_available_slot_index_);\n        swap(last_available_slot_index_, rhs.last_available_slot_index_);\n    }\n\nprotected:\n    // These accessors are not part of P0661R2 but are \"modernized\" versions\n    // of the protected interface of std::priority_queue, std::stack, etc.\n    constexpr Container<mapped_type>& c() & noexcept { return values_; }\n    constexpr const Container<mapped_type>& c() const& noexcept { return values_; }\n    constexpr Container<mapped_type>&& c() && noexcept { return std::move(values_); }\n    constexpr const Container<mapped_type>&& c() const&& noexcept { return std::move(values_); }\n\nprivate:\n    constexpr slot_iterator slot_iter_from_value_iter(const_iterator value_iter) {\n        auto value_index = std::distance(const_iterator(values_.begin()), value_iter);\n        auto slot_index = *std::next(reverse_map_.begin(), value_index);\n        return std::next(slots_.begin(), slot_index);\n    }\n    constexpr iterator erase_slot_iter(slot_iterator slot_iter) {\n        auto slot_index = std::distance(slots_.begin(), slot_iter);\n        auto value_index = get_index(*slot_iter);\n        auto value_iter = std::next(values_.begin(), value_index);\n        auto value_back_iter = std::prev(values_.end());\n        if (value_iter != value_back_iter) {\n            auto slot_back_iter = slot_iter_from_value_iter(value_back_iter);\n            *value_iter = std::move(*value_back_iter);\n            this->set_index(*slot_back_iter, value_index);\n            auto reverse_map_iter = std::next(reverse_map_.begin(), value_index);\n            *reverse_map_iter = static_cast<key_index_type>(std::distance(slots_.begin(), slot_back_iter));\n        }\n        values_.pop_back();\n        reverse_map_.pop_back();\n        // Expire this key.\n        if (next_available_slot_index_ == slots_.size()) {\n            next_available_slot_index_ = static_cast<key_index_type>(slot_index);\n            last_available_slot_index_ = static_cast<key_index_type>(slot_index);\n        } else {\n            auto last_slot_iter = std::next(slots_.begin(), last_available_slot_index_);\n            this->set_index(*last_slot_iter, slot_index);\n            last_available_slot_index_ = static_cast<key_index_type>(slot_index);\n        }\n        this->increment_generation(*slot_iter);\n        return std::next(values_.begin(), value_index);\n    }\n\n    Container<key_type> slots_;  // high_water_mark() entries\n    Container<key_index_type> reverse_map_;  // exactly size() entries\n    Container<mapped_type> values_;  // exactly size() entries\n    key_index_type next_available_slot_index_{};\n    key_index_type last_available_slot_index_{};\n\n    // Class invariant:\n    // Either next_available_slot_index_ == last_available_slot_index_ == slots_.size(),\n    // or else 0 <= next_available_slot_index_ < slots_.size() and the \"key\" of that slot\n    // entry points to the subsequent available slot, and so on, until reaching\n    // last_available_slot_index_ (which might equal next_available_slot_index_ if there\n    // is only one available slot at the moment).\n};\n\ntemplate<class T, class Key, template<class...> class Container>\nconstexpr void swap(slot_map<T, Key, Container>& lhs, slot_map<T, Key, Container>& rhs) {\n    lhs.swap(rhs);\n}\n\n} // namespace stdext\n"
  },
  {
    "path": "SG14_test/SG14_test.h",
    "content": "#if !defined SG14_TEST_2015_06_11_18_24\n#define SG14_TEST_2015_06_11_18_24\n\n#undef NDEBUG\n\nnamespace sg14_test\n{\n    void flat_map_test();\n    void flat_set_test();\n    void inplace_function_test();\n    void plf_colony_test();\n    void ring_test();\n    void slot_map_test();\n    void uninitialized_test();\n    void unstable_remove_test();\n}\n\n#endif\n"
  },
  {
    "path": "SG14_test/flat_map_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include \"flat_map.h\"\n#include <assert.h>\n#include <deque>\n#include <functional>\n#include <list>\n#if __has_include(<memory_resource>)\n#include <memory_resource>\n#endif\n#include <string>\n#include <vector>\n\nnamespace {\n\nstruct AmbiguousEraseWidget {\n    explicit AmbiguousEraseWidget(const char *s) : s_(s) {}\n\n    template<class T>\n    AmbiguousEraseWidget(T) : s_(\"notfound\") {}\n\n    friend bool operator<(const AmbiguousEraseWidget& a, const AmbiguousEraseWidget& b) {\n        return a.s_ < b.s_;\n    }\n\nprivate:\n    std::string s_;\n};\n\nstruct InstrumentedWidget {\n    static int move_ctors, copy_ctors;\n    InstrumentedWidget() = delete;\n    InstrumentedWidget(const char *s) : s_(s) {}\n    InstrumentedWidget(InstrumentedWidget&& o) noexcept : s_(std::move(o.s_)) { o.is_moved_from = true; move_ctors += 1; }\n    InstrumentedWidget(const InstrumentedWidget& o) : s_(o.s_) { copy_ctors += 1; }\n    InstrumentedWidget& operator=(InstrumentedWidget&& o) noexcept {\n        s_ = std::move(o.s_);\n        o.is_moved_from = true;\n        return *this;\n    }\n    InstrumentedWidget& operator=(const InstrumentedWidget&) = default;\n\n    friend bool operator<(const InstrumentedWidget& a, const InstrumentedWidget& b) {\n        return a.s_ < b.s_;\n    }\n    std::string str() const { return s_; }\n\n    bool is_moved_from = false;\nprivate:\n    std::string s_;\n};\nint InstrumentedWidget::move_ctors = 0;\nint InstrumentedWidget::copy_ctors = 0;\n\nstatic void AmbiguousEraseTest()\n{\n    stdext::flat_map<AmbiguousEraseWidget, int> fs;\n    fs.emplace(\"a\", 1);\n    fs.emplace(\"b\", 2);\n    fs.emplace(\"c\", 3);\n    assert(fs.size() == 3);\n    fs.erase(AmbiguousEraseWidget(\"a\"));  // calls erase(const Key&)\n    assert(fs.size() == 2);\n    fs.erase(fs.begin());                 // calls erase(iterator)\n    assert(fs.size() == 1);\n    fs.erase(fs.cbegin());                // calls erase(const_iterator)\n    assert(fs.size() == 0);\n}\n\nstatic void ExtractDoesntSwapTest()\n{\n#if defined(__cpp_lib_memory_resource)\n    // This test fails if extract() is implemented in terms of swap().\n    {\n        std::pmr::monotonic_buffer_resource mr;\n        std::pmr::polymorphic_allocator<int> a(&mr);\n        stdext::flat_map<int, int, std::less<>, std::pmr::vector<int>, std::pmr::vector<int>> fs({{1, 10}, {2, 20}}, a);\n        auto ctrs = std::move(fs).extract();\n        assert(ctrs.keys.get_allocator() == a);\n        assert(ctrs.values.get_allocator() == a);\n    }\n#endif\n\n    // Sanity-check with std::allocator, even though this can't fail.\n    {\n        std::allocator<int> a;\n        stdext::flat_map<int, int, std::less<>, std::vector<int>, std::vector<int>> fs({{1, 10}, {2, 20}}, a);\n        auto ctrs = std::move(fs).extract();\n        assert(ctrs.keys.get_allocator() == a);\n        assert(ctrs.values.get_allocator() == a);\n    }\n}\n\nstatic void MoveOperationsPilferOwnership()\n{\n    using FS = stdext::flat_map<InstrumentedWidget, int>;\n    InstrumentedWidget::move_ctors = 0;\n    InstrumentedWidget::copy_ctors = 0;\n    FS fs;\n    fs.insert(std::make_pair(InstrumentedWidget(\"abc\"), 1));\n    assert(InstrumentedWidget::move_ctors == 3);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    fs.emplace(InstrumentedWidget(\"def\"), 1); fs.erase(\"def\");  // poor man's reserve()\n    InstrumentedWidget::copy_ctors = 0;\n    InstrumentedWidget::move_ctors = 0;\n\n    fs.emplace(\"def\", 1);  // is still not directly emplaced; a temporary is created to find()\n    assert(InstrumentedWidget::move_ctors == 1);\n    assert(InstrumentedWidget::copy_ctors == 0);\n    InstrumentedWidget::move_ctors = 0;\n\n    FS fs2 = std::move(fs);  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    fs = std::move(fs2);  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    FS fs3(fs, std::allocator<InstrumentedWidget>());\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 2);\n    InstrumentedWidget::copy_ctors = 0;\n\n    FS fs4(std::move(fs), std::allocator<InstrumentedWidget>());  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n}\n\nstatic void SortedUniqueConstructionTest()\n{\n    auto a = stdext::sorted_unique;\n    stdext::sorted_unique_t b;\n    stdext::sorted_unique_t c{};\n    (void)a; (void)b; (void)c;\n\n#if 0 // TODO: GCC cannot compile this\n    struct explicitness_tester {\n        bool test(std::vector<int>) { return true; }\n        bool test(stdext::sorted_unique_t) { return false; }\n    };\n    explicitness_tester tester;\n    assert(tester.test({}) == true);\n#endif\n}\n\nstatic void TryEmplaceTest()\n{\n    stdext::flat_map<int, InstrumentedWidget> fm;\n    std::pair<stdext::flat_map<int, InstrumentedWidget>::iterator, bool> pair;\n    if (true) {\n        // try_emplace for a non-existent key does move-from.\n        InstrumentedWidget w(\"abc\");\n        pair = fm.try_emplace(1, std::move(w));\n        assert(w.is_moved_from);\n        assert(pair.second);\n    }\n    if (true) {\n        // try_emplace over an existing key is a no-op.\n        InstrumentedWidget w(\"def\");\n        pair = fm.try_emplace(1, std::move(w));\n        assert(!w.is_moved_from);\n        assert(!pair.second);\n        assert(pair.first->first == 1);\n        assert(pair.first->second.str() == \"abc\");\n    }\n    if (true) {\n        // emplace for a non-existent key does move-from.\n        InstrumentedWidget w(\"abc\");\n        pair = fm.emplace(2, std::move(w));\n        assert(w.is_moved_from);\n        assert(pair.second);\n        assert(pair.first->first == 2);\n        assert(pair.first->second.str() == \"abc\");\n    }\n    if (true) {\n        // emplace over an existing key is a no-op, but does move-from in order to construct the pair.\n        InstrumentedWidget w(\"def\");\n        pair = fm.emplace(2, std::move(w));\n        assert(w.is_moved_from);\n        assert(!pair.second);\n        assert(pair.first->first == 2);\n        assert(pair.first->second.str() == \"abc\");\n    }\n    if (true) {\n        // insert-or-assign for a non-existent key does move-construct.\n        InstrumentedWidget w(\"abc\");\n        pair = fm.insert_or_assign(3, std::move(w));\n        assert(w.is_moved_from);\n        assert(pair.second);\n        assert(pair.first->first == 3);\n        assert(pair.first->second.str() == \"abc\");\n    }\n    if (true) {\n        // insert-or-assign over an existing key does a move-assign.\n        InstrumentedWidget w(\"def\");\n        pair = fm.insert_or_assign(3, std::move(w));\n        assert(w.is_moved_from);\n        assert(!pair.second);\n        assert(pair.first->first == 3);\n        assert(pair.first->second.str() == \"def\");\n    }\n}\n\nstatic void VectorBoolSanityTest()\n{\n    using FM = stdext::flat_map<bool, bool>;\n    FM fm;\n    auto it_inserted = fm.emplace(true, false);\n    assert(it_inserted.second);\n    auto it = it_inserted.first;\n    assert(it == fm.begin());\n    assert(it->first == true); assert(it->first);\n    assert(it->second == false); assert(!it->second);\n    it->second = false;\n    assert(fm.size() == 1);\n    it = fm.emplace_hint(it, false, true);\n    assert(it == fm.begin());\n    assert(it->first == false); assert(!it->first);\n    assert(it->second == true); assert(it->second);\n    it->second = true;\n    assert(fm.size() == 2);\n    auto count = fm.erase(false);\n    assert(count == 1);\n    assert(fm.size() == 1);\n    it = fm.erase(fm.begin());\n    assert(fm.empty());\n    assert(it == fm.begin());\n    assert(it == fm.end());\n\n    assert(fm.find(true) == fm.end());\n    fm.try_emplace(true, true);\n    assert(fm.find(true) != fm.end());\n    assert(fm[true] == true);\n    fm[true] = false;\n    assert(fm.find(true) != fm.end());\n    assert(fm[true] == false);\n    fm.clear();\n}\n\n#if defined(__cpp_deduction_guides)\nstatic bool free_function_less(const int& a, const int& b) {\n    return (a < b);\n}\n\ntemplate<class... Args>\nstatic auto flatmap_is_ctadable_from(int, Args&&... args)\n    -> decltype(flat_map(std::forward<Args>(args)...), std::true_type{})\n{\n    return {};\n}\n\ntemplate<class... Args>\nstatic auto flatmap_is_ctadable_from(long, Args&&...)\n    -> std::false_type\n{\n    return {};\n}\n#endif // defined(__cpp_deduction_guides)\n\n\nstatic void DeductionGuideTests()\n{\n    using stdext::flat_map;\n#if defined(__cpp_deduction_guides)\n    if (true) {\n        // flat_map(Container)\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(v);\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        flat_map fm2 = flat_map(std::deque<std::pair<std::string, int>>());\n        static_assert(std::is_same_v<decltype(fm2), flat_map<std::string, int>>);\n        std::list<std::pair<const int* const, const int*>> lst;\n        flat_map fm3(lst);\n        static_assert(std::is_same_v<decltype(fm3), flat_map<const int*, const int*>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        flat_map fm4(pv);\n        static_assert(std::is_same_v<decltype(fm4), flat_map<std::pmr::string, int>>);\n#endif\n        std::initializer_list<std::pair<int, std::string>> il = {{1,\"c\"}, {5,\"b\"}, {3,\"a\"}};\n        flat_map fm5(il);\n        static_assert(std::is_same_v<decltype(fm5), flat_map<int, std::string>>);\n        assert(fm5.size() == 3);\n        assert(( fm5 == decltype(fm5)(stdext::sorted_unique, {{1,\"c\"}, {3,\"a\"}, {5,\"b\"}}) ));\n    }\n    if (true) {\n        // flat_map(KeyContainer, MappedContainer)\n        std::vector<int> vi {2,1};\n        std::vector<std::string> vs {\"a\",\"b\"};\n        flat_map fm1(vi, vs);\n        static_assert(std::is_same_v<decltype(fm1), flat_map<int, std::string>>);\n        assert(( fm1 == flat_map<int, std::string>(stdext::sorted_unique, {{1,\"b\"}, {2,\"a\"}}) ));\n        flat_map fm2(std::move(vs), std::move(vi));\n        static_assert(std::is_same_v<decltype(fm2), flat_map<std::string, int>>);\n        assert(( fm2 == flat_map<std::string, int>(stdext::sorted_unique, {{\"a\",2}, {\"b\",1}}) ));\n    }\n    if (true) {\n        // flat_map(Container, Allocator)\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(v, std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        // TODO: neither of these lines compiles, and it's unclear what is INTENDED to happen\n        // flat_map fm2(pv, std::allocator<int>());\n        // flat_map fm2(pv, std::pmr::polymorphic_allocator<int>());\n#endif\n    }\n    if (true) {\n        // flat_map(KeyContainer, MappedContainer, Allocator)\n        std::vector<int> vi {2,1};\n        std::vector<std::string> vs {\"a\",\"b\"};\n        flat_map fm1(vi, vs, std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<int, std::string>>);\n        assert(( fm1 == decltype(fm1)(stdext::sorted_unique, {{1,\"b\"}, {2,\"a\"}}) ));\n#if __cpp_lib_memory_resource\n        std::pmr::vector<int> pvi {2,1};\n        std::pmr::vector<std::pmr::string> pvs {\"a\",\"b\"};\n        flat_map fm2(pvi, pvs, std::pmr::polymorphic_allocator<char>());\n        static_assert(std::is_same_v<decltype(fm2), flat_map<int, std::pmr::string, std::less<int>, std::pmr::vector<int>, std::pmr::vector<std::pmr::string>>>);\n        assert(( fm2 == decltype(fm2)(stdext::sorted_unique, {{1,\"b\"}, {2,\"a\"}}) ));\n#endif\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, Container)\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(stdext::sorted_unique, v);\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        flat_map fm2 = flat_map(stdext::sorted_unique, std::deque<std::pair<std::string, int>>());\n        static_assert(std::is_same_v<decltype(fm2), flat_map<std::string, int>>);\n        std::list<std::pair<const int* const, const int*>> lst;\n        flat_map fm3(stdext::sorted_unique, lst);\n        static_assert(std::is_same_v<decltype(fm3), flat_map<const int*, const int*>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        flat_map fm4(stdext::sorted_unique, pv);\n        static_assert(std::is_same_v<decltype(fm4), flat_map<std::pmr::string, int>>);\n#endif\n        std::initializer_list<std::pair<int, std::string>> il = {{1,\"c\"}, {3,\"b\"}, {5,\"a\"}};\n        flat_map fm5(stdext::sorted_unique, il);\n        static_assert(std::is_same_v<decltype(fm5), flat_map<int, std::string>>);\n        assert(( fm5 == decltype(fm5)(stdext::sorted_unique, {{1,\"c\"}, {3,\"b\"}, {5,\"a\"}}) ));\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, KeyContainer, MappedContainer)\n        std::vector<int> vi {1,2};\n        std::vector<std::string> vs {\"a\",\"b\"};\n        flat_map fm1(stdext::sorted_unique, vi, vs);\n        static_assert(std::is_same_v<decltype(fm1), flat_map<int, std::string>>);\n        assert(( fm1 == decltype(fm1)(stdext::sorted_unique, {{1,\"a\"}, {2,\"b\"}}) ));\n        flat_map fm2(stdext::sorted_unique, std::move(vs), std::move(vi));\n        static_assert(std::is_same_v<decltype(fm2), flat_map<std::string, int>>);\n        assert(( fm2 == decltype(fm2)(stdext::sorted_unique, {{\"a\",1}, {\"b\",2}}) ));\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, Container, Allocator)\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(stdext::sorted_unique, v, std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        // TODO: neither of these lines compiles, and it's unclear what is INTENDED to happen\n        // flat_map fm2(stdext::sorted_unique, pv, std::allocator<int>());\n        // flat_map fm2(stdext::sorted_unique, pv, std::pmr::polymorphic_allocator<int>());\n#endif\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, KeyContainer, MappedContainer, Allocator)\n        std::vector<int> vi {2,1};\n        std::vector<std::string> vs {\"a\",\"b\"};\n        flat_map fm1(stdext::sorted_unique, vs, vi, std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        assert(( fm1 == decltype(fm1)(stdext::sorted_unique, {{\"a\",2}, {\"b\",1}}) ));\n#if __cpp_lib_memory_resource\n        std::pmr::vector<int> pvi {1, 2};\n        std::pmr::vector<std::pmr::string> pvs {\"b\",\"a\"};\n        flat_map fm2(stdext::sorted_unique, pvi, pvs, std::pmr::polymorphic_allocator<char>());\n        static_assert(std::is_same_v<decltype(fm2), flat_map<int, std::pmr::string, std::less<int>, std::pmr::vector<int>, std::pmr::vector<std::pmr::string>>>);\n        assert(( fm2 == decltype(fm2)(stdext::sorted_unique, {{1,\"b\"}, {2,\"a\"}}) ));\n#endif\n    }\n    if (true) {\n        // flat_map(InputIterator, InputIterator, Compare = Compare())\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(v.begin(), v.end());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        std::list<std::pair<const int* const, const int*>> lst;\n        flat_map fm3(lst.begin(), lst.end());\n        static_assert(std::is_same_v<decltype(fm3), flat_map<const int*, const int*>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        flat_map fm4(pv.begin(), pv.end());\n        static_assert(std::is_same_v<decltype(fm4), flat_map<std::pmr::string, int>>);\n#endif\n        std::initializer_list<std::pair<int, std::string>> il = {{1,\"c\"}, {5,\"b\"}, {3,\"a\"}};\n        flat_map fm5(il.begin(), il.end());\n        static_assert(std::is_same_v<decltype(fm5), flat_map<int, std::string>>);\n        assert(( fm5 == decltype(fm5)(stdext::sorted_unique, {{1,\"c\"}, {3,\"a\"}, {5,\"b\"}}) ));\n    }\n    if (true) {\n        // flat_map(InputIterator, InputIterator, Compare = Compare())\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(v.begin(), v.end(), std::less<std::string>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        int x = 3;\n        std::pair<int, int> arr[] = {{1,2}, {2,3}, {3,4}, {4,5}};\n        flat_map fm2(arr, arr + 4, [&x](int a, int b){ return (a % x) < (b % x); });\n        assert(fm2.key_comp()(2, 4) == false);\n        x = 10;\n        assert(fm2.key_comp()(2, 4) == true);\n        x = 3;\n        assert(fm2.begin()[0].first == 3);\n        std::list<std::pair<const int* const, const int*>> lst;\n        flat_map fm3(lst.begin(), lst.end(), std::greater<>());\n        static_assert(std::is_same_v<decltype(fm3), flat_map<const int*, const int*, std::greater<>>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        flat_map fm4(pv.begin(), pv.end(), std::greater<std::pmr::string>());\n        static_assert(std::is_same_v<decltype(fm4), flat_map<std::pmr::string, int, std::greater<std::pmr::string>>>);\n#endif\n        std::initializer_list<std::pair<int, std::string>> il = {{1,\"c\"}, {5,\"b\"}, {3,\"a\"}};\n        flat_map fm5(il.begin(), il.end(), std::less<int>());\n        static_assert(std::is_same_v<decltype(fm5), flat_map<int, std::string>>);\n        assert(( fm5 == decltype(fm5)(stdext::sorted_unique, {{1,\"c\"}, {3,\"a\"}, {5,\"b\"}}) ));\n\n        flat_map fm6(arr, arr + 4, free_function_less);\n        static_assert(std::is_same_v<decltype(fm6), flat_map<int, int, bool(*)(const int&, const int&)>>);\n        assert(fm6.key_comp() == free_function_less);\n        assert(( fm6 == decltype(fm6)(stdext::sorted_unique, {{1,2}, {2,3}, {3,4}, {4,5}}, free_function_less) ));\n    }\n    if (true) {\n        // flat_map(InputIterator, InputIterator, Compare, Allocator)\n        std::vector<std::pair<std::string, int>> v;\n        flat_map fm1(v.begin(), v.end(), std::less<std::string>(), std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm1), flat_map<std::string, int>>);\n        int x = 3;\n        std::pair<int, int> arr[] = {{1,2}, {2,3}, {3,4}, {4,5}};\n        flat_map fm2(arr, arr + 4, [&x](int a, int b){ return (a % x) < (b % x); }, std::allocator<int>());\n        assert(fm2.key_comp()(2, 4) == false);\n        x = 10;\n        assert(fm2.key_comp()(2, 4) == true);\n        x = 3;\n        assert(fm2.begin()[0].first == 3);\n        std::list<std::pair<const int* const, const int*>> lst;\n        flat_map fm3(lst.begin(), lst.end(), std::greater<>(), std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm3), flat_map<const int*, const int*, std::greater<>>>);\n#if __cpp_lib_memory_resource\n        std::pmr::vector<std::pair<std::pmr::string, int>> pv;\n        flat_map fm4(pv.begin(), pv.end(), std::greater<>(), std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm4), flat_map<std::pmr::string, int, std::greater<>>>);\n        assert(!flatmap_is_ctadable_from(0, pv.begin(), pv.end(), std::greater<int>(), std::pmr::polymorphic_allocator<int>()));\n#endif\n        std::initializer_list<std::pair<int, std::string>> il = {{1,\"c\"}, {5,\"b\"}, {3,\"a\"}};\n        flat_map fm5(il.begin(), il.end(), std::less<int>(), std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm5), flat_map<int, std::string>>);\n        assert(( fm5 == decltype(fm5)(stdext::sorted_unique, {{1,\"c\"}, {3,\"a\"}, {5,\"b\"}}) ));\n\n        flat_map fm6(arr, arr + 4, free_function_less, std::allocator<int>());\n        static_assert(std::is_same_v<decltype(fm6), flat_map<int, int, bool(*)(const int&, const int&)>>);\n        assert(fm6.key_comp() == free_function_less);\n        assert(( fm6 == decltype(fm6)(stdext::sorted_unique, {{1,2}, {2,3}, {3,4}, {4,5}}, free_function_less) ));\n    }\n    if (true) {\n        // flat_map(InputIterator, InputIterator, Allocator)\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, InputIterator, InputIterator, Compare = Compare())\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, InputIterator, InputIterator, Compare, Allocator)\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, InputIterator, InputIterator, Allocator)\n    }\n    if (true) {\n        // flat_map(std::initializer_list<std::pair<const Key, T>>, Compare = Compare())\n    }\n    if (true) {\n        // flat_map(std::initializer_list<std::pair<const Key, T>>, Compare, Allocator)\n    }\n    if (true) {\n        // flat_map(std::initializer_list<std::pair<const Key, T>>, Allocator)\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Compare = Compare())\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Compare, Allocator)\n    }\n    if (true) {\n        // flat_map(sorted_unique_t, std::initializer_list<std::pair<const Key, T>>, Allocator)\n    }\n#endif // defined(__cpp_deduction_guides)\n}\n\ntemplate<class FS>\nstatic void ConstructionTest()\n{\n    static_assert(std::is_same<int, typename FS::key_type>::value, \"\");\n    static_assert(std::is_convertible<const char*, typename FS::mapped_type>::value, \"\");\n    using Mapped = typename FS::mapped_type;\n    using Str = std::conditional_t<std::is_same<Mapped, const char *>::value, std::string, Mapped>;\n    using Compare = typename FS::key_compare;\n    std::vector<int> keys = {1, 3, 5};\n    std::vector<const char*> values = {\"a\", \"c\", \"b\"};\n    std::vector<std::pair<int, const char*>> pairs = {\n        {1, \"a\"},\n        {3, \"c\"},\n        {5, \"b\"},\n    };\n    if (true) {\n        FS fs;  // default constructor\n        fs = {\n            {1, \"a\"},\n            {3, \"c\"},\n            {5, \"b\"},\n        };\n        assert(std::is_sorted(fs.keys().begin(), fs.keys().end(), fs.key_comp()));\n        assert(std::is_sorted(fs.begin(), fs.end(), fs.value_comp()));\n        assert(fs[1] == Str(\"a\"));\n        assert(fs[3] == Str(\"c\"));\n        assert(fs[5] == Str(\"b\"));\n    }\n    for (auto&& fs : {\n        FS({{1, \"a\"}, {3, \"c\"}, {5, \"b\"}}),\n        FS(pairs.begin(), pairs.end()),\n        FS(pairs.rbegin(), pairs.rend()),\n        FS(pairs, Compare()),\n        FS({{1, \"a\"}, {3, \"c\"}, {5, \"b\"}}, Compare()),\n        FS(pairs.begin(), pairs.end(), Compare()),\n        FS(pairs.rbegin(), pairs.rend(), Compare()),\n    }) {\n        assert(std::is_sorted(fs.keys().begin(), fs.keys().end(), fs.key_comp()));\n        assert(std::is_sorted(fs.begin(), fs.end(), fs.value_comp()));\n        assert(fs.find(0) == fs.end());\n        assert(fs.find(1) != fs.end());\n        assert(fs.find(2) == fs.end());\n        assert(fs.find(3) != fs.end());\n        assert(fs.find(4) == fs.end());\n        assert(fs.find(5) != fs.end());\n        assert(fs.find(6) == fs.end());\n        assert(fs.at(1) == Str(\"a\"));\n        assert(fs.at(3) == Str(\"c\"));\n        assert(fs.find(5)->second == Str(\"b\"));\n    }\n    if (std::is_sorted(keys.begin(), keys.end(), Compare())) {\n        for (auto&& fs : {\n            FS(stdext::sorted_unique, pairs),\n            FS(stdext::sorted_unique, pairs.begin(), pairs.end()),\n            FS(stdext::sorted_unique, {{1, \"a\"}, {3, \"c\"}, {5, \"b\"}}),\n            FS(stdext::sorted_unique, pairs, Compare()),\n            FS(stdext::sorted_unique, pairs.begin(), pairs.end(), Compare()),\n            FS(stdext::sorted_unique, {{1, \"a\"}, {3, \"c\"}, {5, \"b\"}}, Compare()),\n        }) {\n            assert(std::is_sorted(fs.keys().begin(), fs.keys().end(), fs.key_comp()));\n            assert(std::is_sorted(fs.begin(), fs.end(), fs.value_comp()));\n            assert(fs.at(1) == Str(\"a\"));\n            assert(fs.at(3) == Str(\"c\"));\n            assert(fs.find(5)->second == Str(\"b\"));\n        }\n    }\n}\n\ntemplate<class FM>\nstatic void InsertOrAssignTest()\n{\n    FM fm;\n    const char *str = \"a\";\n    using Mapped = typename FM::mapped_type;\n    using Str = std::conditional_t<std::is_same<Mapped, const char *>::value, std::string, Mapped>;\n\n    fm.insert_or_assign(1, str);\n    assert(fm.at(1) == Str(\"a\"));\n    assert(fm[1] == Str(\"a\"));\n    fm.insert_or_assign(2, std::move(str));\n    assert(fm.at(2) == Str(\"a\"));\n    assert(fm[2] == Str(\"a\"));\n    fm.insert_or_assign(2, \"b\");\n    assert(fm.at(2) == Str(\"b\"));\n    assert(fm[2] == Str(\"b\"));\n    fm.insert_or_assign(3, \"c\");\n    assert(fm.at(3) == Str(\"c\"));\n    assert(fm[3] == Str(\"c\"));\n\n    // With hints.\n    fm.insert_or_assign(fm.begin(), 1, str);\n    assert(fm.at(1) == Str(\"a\"));\n    assert(fm[1] == Str(\"a\"));\n    fm.insert_or_assign(fm.begin()+2, 2, std::move(str));\n    assert(fm.at(2) == Str(\"a\"));\n    assert(fm[2] == Str(\"a\"));\n    fm.insert_or_assign(fm.end(), 2, \"c\");\n    assert(fm.at(2) == Str(\"c\"));\n    assert(fm[2] == Str(\"c\"));\n    fm.insert_or_assign(fm.end() - 1, 3, \"b\");\n    assert(fm.at(3) == Str(\"b\"));\n    assert(fm[3] == Str(\"b\"));\n}\n\n\ntemplate<class FS>\nstatic void SpecialMemberTest()\n{\n    static_assert(std::is_default_constructible<FS>::value, \"\");\n    static_assert(std::is_nothrow_move_constructible<FS>::value == std::is_nothrow_move_constructible<typename FS::key_container_type>::value && std::is_nothrow_move_constructible<typename FS::mapped_container_type>::value && std::is_nothrow_move_constructible<typename FS::key_compare>::value, \"\");\n    static_assert(std::is_copy_constructible<FS>::value, \"\");\n    static_assert(std::is_copy_assignable<FS>::value, \"\");\n    static_assert(std::is_move_assignable<FS>::value, \"\");\n    static_assert(std::is_nothrow_destructible<FS>::value, \"\");\n\n    static_assert(std::is_default_constructible<typename FS::containers>::value, \"\");\n    static_assert(std::is_nothrow_move_constructible<typename FS::containers>::value == std::is_nothrow_move_constructible<typename FS::key_container_type>::value && std::is_nothrow_move_constructible<typename FS::mapped_container_type>::value, \"\");\n    static_assert(std::is_copy_constructible<typename FS::containers>::value, \"\");\n    static_assert(std::is_copy_assignable<typename FS::containers>::value, \"\");\n    static_assert(std::is_move_assignable<typename FS::containers>::value, \"\");\n    static_assert(std::is_nothrow_destructible<typename FS::containers>::value, \"\");\n}\n\ntemplate<class FM>\nstatic void ComparisonOperatorsTest()\n{\n    const char *abc[] = {\"\", \"a\", \"b\", \"c\"};\n    FM fm1 = {\n        {1, abc[2]}, {2, abc[3]},\n    };\n    FM fm2 = {\n        {1, abc[2]}, {2, abc[3]},\n    };\n    // {1b, 2c} is equal to {1b, 2c}.\n    assert(fm1 == fm2);\n    assert(!(fm1 != fm2));\n    assert(!(fm1 < fm2));\n    assert(!(fm1 > fm2));\n    assert(fm1 <= fm2);\n    assert(fm1 >= fm2);\n\n    fm2[2] = abc[1];\n    // {1b, 2c} is greater than {1b, 2a}.\n    assert(!(fm1 == fm2));\n    assert(fm1 != fm2);\n    assert(!(fm1 < fm2));\n    assert(fm1 > fm2);\n    assert(!(fm1 <= fm2));\n    assert(fm1 >= fm2);\n\n    fm2.erase(2);\n    fm2.insert({0, abc[3]});\n    // {1b, 2c} is greater than {0c, 1b}.\n    assert(!(fm1 == fm2));\n    assert(fm1 != fm2);\n    assert(!(fm1 < fm2));\n    assert(fm1 > fm2);\n    assert(!(fm1 <= fm2));\n    assert(fm1 >= fm2);\n}\n\ntemplate<class FM>\nstatic void SearchTest()\n{\n    FM fm{{1, \"a\"}, {2, \"b\"}, {3, \"c\"}};\n    auto it = fm.lower_bound(2);\n    auto cit = const_cast<const FM&>(fm).lower_bound(2);\n    assert(it == fm.begin() + 1);\n    assert(cit == it);\n\n    it = fm.upper_bound(2);\n    cit = const_cast<const FM&>(fm).upper_bound(2);\n    assert(it == fm.begin() + 2);\n    assert(cit == it);\n\n    auto itpair = fm.equal_range(2);\n    auto citpair = const_cast<const FM&>(fm).equal_range(2);\n    assert(itpair.first == fm.begin() + 1);\n    assert(itpair.second == fm.begin() + 2);\n    assert(citpair == decltype(citpair)(itpair));\n\n    static_assert(std::is_same<decltype(it), typename FM::iterator>::value, \"\");\n    static_assert(std::is_same<decltype(cit), typename FM::const_iterator>::value, \"\");\n}\n\n} // anonymous namespace\n\nvoid sg14_test::flat_map_test()\n{\n    AmbiguousEraseTest();\n    ExtractDoesntSwapTest();\n    MoveOperationsPilferOwnership();\n    SortedUniqueConstructionTest();\n    TryEmplaceTest();\n    VectorBoolSanityTest();\n    DeductionGuideTests();\n\n    // Test the most basic flat_set.\n    {\n        using FS = stdext::flat_map<int, const char*>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n\n    // Test a custom comparator.\n    {\n        using FS = stdext::flat_map<int, const char*, std::greater<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n\n    // Test a transparent comparator.\n    {\n        using FS = stdext::flat_map<int, const char*, std::greater<>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n\n    // Test a custom container.\n    {\n        using FS = stdext::flat_map<int, const char*, std::less<int>, std::deque<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n\n#if defined(__cpp_lib_memory_resource)\n    // Test a pmr container.\n    {\n        using FS = stdext::flat_map<int, const char*, std::less<int>, std::pmr::vector<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n\n    // Test a pmr container with uses-allocator construction!\n    {\n        using FS = stdext::flat_map<int, std::pmr::string, std::less<int>, std::pmr::vector<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n        InsertOrAssignTest<FS>();\n        ComparisonOperatorsTest<FS>();\n        SearchTest<FS>();\n    }\n#endif\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::flat_map_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/flat_set_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include \"flat_set.h\"\n#include <assert.h>\n#include <deque>\n#include <functional>\n#if __has_include(<memory_resource>)\n#include <memory_resource>\n#endif\n#include <string>\n#include <vector>\n\nnamespace {\n\nstruct AmbiguousEraseWidget {\n    friend bool operator<(const AmbiguousEraseWidget& a, const AmbiguousEraseWidget& b) {\n        return a.s_ < b.s_;\n    }\n\n    using iterator = stdext::flat_set<AmbiguousEraseWidget>::iterator;\n    using const_iterator = stdext::flat_set<AmbiguousEraseWidget>::const_iterator;\n\n    explicit AmbiguousEraseWidget(const char *s) : s_(s) {}\n    AmbiguousEraseWidget(iterator) : s_(\"notfound\") {}\n    AmbiguousEraseWidget(const_iterator) : s_(\"notfound\") {}\n\nprivate:\n    std::string s_;\n};\n\nstruct InstrumentedWidget {\n    static int move_ctors, copy_ctors;\n    InstrumentedWidget(const char *s) : s_(s) {}\n    InstrumentedWidget(InstrumentedWidget&& o) : s_(std::move(o.s_)) { move_ctors += 1; }\n    InstrumentedWidget(const InstrumentedWidget& o) : s_(o.s_) { copy_ctors += 1; }\n    InstrumentedWidget& operator=(InstrumentedWidget&&) = default;\n    InstrumentedWidget& operator=(const InstrumentedWidget&) = default;\n\n    friend bool operator<(const InstrumentedWidget& a, const InstrumentedWidget& b) {\n        return a.s_ < b.s_;\n    }\n\nprivate:\n    std::string s_;\n};\nint InstrumentedWidget::move_ctors = 0;\nint InstrumentedWidget::copy_ctors = 0;\n\nstatic void AmbiguousEraseTest()\n{\n    stdext::flat_set<AmbiguousEraseWidget> fs;\n    fs.emplace(\"a\");\n    fs.emplace(\"b\");\n    fs.emplace(\"c\");\n    assert(fs.size() == 3);\n    fs.erase(AmbiguousEraseWidget(\"a\"));  // calls erase(const Key&)\n    assert(fs.size() == 2);\n    fs.erase(fs.cbegin());                // calls erase(const_iterator)\n    assert(fs.size() == 1);\n#if __cplusplus >= 201703L\n    fs.erase(fs.begin());                 // calls erase(iterator)\n    assert(fs.size() == 0);\n#endif\n}\n\nstatic void ExtractDoesntSwapTest()\n{\n#if defined(__cpp_lib_memory_resource)\n    // This test fails if extract() is implemented in terms of swap().\n    {\n        std::pmr::monotonic_buffer_resource mr;\n        std::pmr::polymorphic_allocator<int> a(&mr);\n        stdext::flat_set<int, std::less<int>, std::pmr::vector<int>> fs({1, 2}, a);\n        std::pmr::vector<int> v = std::move(fs).extract();\n        assert(v.get_allocator() == a);\n        assert(fs.empty());\n    }\n#endif\n\n    // Sanity-check with std::allocator, even though this can't fail.\n    {\n        std::allocator<int> a;\n        stdext::flat_set<int, std::less<int>, std::vector<int>> fs({1, 2}, a);\n        std::vector<int> v = std::move(fs).extract();\n        assert(v.get_allocator() == a);\n        assert(fs.empty());\n    }\n}\n\nstruct ThrowingSwapException {};\n\nstruct ComparatorWithThrowingSwap {\n    std::function<bool(int, int)> cmp_;\n    static bool please_throw;\n    ComparatorWithThrowingSwap(std::function<bool(int, int)> f) : cmp_(f) {}\n    friend void swap(ComparatorWithThrowingSwap& a, ComparatorWithThrowingSwap& b) {\n        if (please_throw)\n            throw ThrowingSwapException();\n        a.cmp_.swap(b.cmp_);\n    }\n    bool operator()(int a, int b) const {\n        return cmp_(a, b);\n    }\n};\nbool ComparatorWithThrowingSwap::please_throw = false;\n\nstatic void ThrowingSwapDoesntBreakInvariants()\n{\n    using std::swap;\n    stdext::flat_set<int, ComparatorWithThrowingSwap> fsx({1,2,3}, ComparatorWithThrowingSwap(std::less<int>()));\n    stdext::flat_set<int, ComparatorWithThrowingSwap> fsy({4,5,6}, ComparatorWithThrowingSwap(std::greater<int>()));\n\n    if (true) {\n        ComparatorWithThrowingSwap::please_throw = false;\n        swap(fsx, fsy);  // should swap both the comparators and the containers\n        fsx.insert(7);\n        fsy.insert(8);\n        std::vector<int> expected_fsx = {7, 6, 5, 4};\n        std::vector<int> expected_fsy = {1, 2, 3, 8};\n        assert(expected_fsx.size() == fsx.size());\n        assert(std::equal(expected_fsx.begin(), expected_fsx.end(), fsx.begin()));\n        assert(expected_fsy.size() == fsy.size());\n        assert(std::equal(expected_fsy.begin(), expected_fsy.end(), fsy.begin()));\n    }\n\n    // However, if ComparatorWithThrowingSwap::please_throw were\n    // set to `true`, then flat_set's behavior would be undefined.\n}\n\nstatic void VectorBoolSanityTest()\n{\n#if __cplusplus >= 201402L  // C++11 doesn't support vector<bool>::emplace\n    using FS = stdext::flat_set<bool>;\n    FS fs;\n    auto it_inserted = fs.emplace(true);\n    assert(it_inserted.second);\n    auto it = it_inserted.first;\n    assert(it == fs.begin());\n    assert(fs.size() == 1);\n    it = fs.emplace_hint(it, false);\n    assert(it == fs.begin());\n    assert(fs.size() == 2);\n    auto count = fs.erase(false);\n    assert(count == 1);\n    assert(fs.size() == 1);\n    it = fs.erase(fs.begin());\n    assert(fs.empty());\n    assert(it == fs.begin());\n    assert(it == fs.end());\n#endif\n}\n\nstruct VectorBoolEvilComparator {\n    bool operator()(bool a, bool b) const {\n        return a < b;\n    }\n    template<class T, class U>\n    bool operator()(T a, U b) const {\n        static_assert(sizeof(T) < 0, \"should never instantiate this call operator\");\n        return a < b;\n    }\n};\n\nstatic void VectorBoolEvilComparatorTest()\n{\n    using FS = stdext::flat_set<bool, VectorBoolEvilComparator>;\n    FS fs;\n    (void)fs.lower_bound(true);\n    (void)fs.upper_bound(true);\n    (void)fs.equal_range(true);\n    const FS& cfs = fs;\n    (void)cfs.lower_bound(true);\n    (void)cfs.upper_bound(true);\n    (void)cfs.equal_range(true);\n}\n\nstatic void MoveOperationsPilferOwnership()\n{\n    using FS = stdext::flat_set<InstrumentedWidget>;\n    InstrumentedWidget::move_ctors = 0;\n    InstrumentedWidget::copy_ctors = 0;\n    FS fs;\n    fs.insert(InstrumentedWidget(\"abc\"));\n    assert(InstrumentedWidget::move_ctors == 1);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    fs.emplace(InstrumentedWidget(\"def\")); fs.erase(\"def\");  // poor man's reserve()\n    InstrumentedWidget::copy_ctors = 0;\n    InstrumentedWidget::move_ctors = 0;\n\n    fs.emplace(\"def\");  // is still not directly emplaced; a temporary is created to find()\n    assert(InstrumentedWidget::move_ctors == 1);\n    assert(InstrumentedWidget::copy_ctors == 0);\n    InstrumentedWidget::move_ctors = 0;\n\n    FS fs2 = std::move(fs);  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    fs = std::move(fs2);  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n\n    FS fs3(fs, std::allocator<InstrumentedWidget>());\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 2);\n    InstrumentedWidget::copy_ctors = 0;\n\n    FS fs4(std::move(fs), std::allocator<InstrumentedWidget>());  // should just transfer buffer ownership\n    assert(InstrumentedWidget::move_ctors == 0);\n    assert(InstrumentedWidget::copy_ctors == 0);\n}\n\ntemplate<class FS>\nstatic void ConstructionTest()\n{\n    static_assert(std::is_same<int, typename FS::key_type>::value, \"\");\n    static_assert(std::is_same<int, typename FS::value_type>::value, \"\");\n    using Compare = typename FS::key_compare;\n    std::vector<int> vec = {1, 3, 5};\n    if (true) {\n        FS fs;  // default constructor\n        fs = {1, 3, 5};  // assignment operator\n        assert(std::is_sorted(fs.begin(), fs.end(), fs.key_comp()));\n    }\n    if (true) {\n        FS fs {1, 3, 1, 5, 3};\n        assert(fs.size() == 3);  // assert that uniqueing takes place\n        std::vector<int> vec2 = {1, 3, 1, 5, 3};\n        FS fs2(vec2);\n        assert(fs2.size() == 3); // assert that uniqueing takes place\n    }\n    for (auto&& fs : {\n        FS(vec),\n        FS({1, 3, 5}),\n        FS(vec.begin(), vec.end()),\n        FS(vec.rbegin(), vec.rend()),\n        FS(vec, Compare()),\n        FS({1, 3, 5}, Compare()),\n        FS(vec.begin(), vec.end(), Compare()),\n        FS(vec.rbegin(), vec.rend(), Compare()),\n    }) {\n        auto cmp = fs.key_comp();\n        assert(std::is_sorted(fs.begin(), fs.end(), cmp));\n        assert(fs.find(0) == fs.end());\n        assert(fs.find(1) != fs.end());\n        assert(fs.find(2) == fs.end());\n        assert(fs.find(3) != fs.end());\n        assert(fs.find(4) == fs.end());\n        assert(fs.find(5) != fs.end());\n        assert(fs.find(6) == fs.end());\n    }\n    if (std::is_sorted(vec.begin(), vec.end(), Compare())) {\n        for (auto&& fs : {\n            FS(stdext::sorted_unique, vec),\n            FS(stdext::sorted_unique, vec.begin(), vec.end()),\n            FS(stdext::sorted_unique, {1, 3, 5}),\n            FS(stdext::sorted_unique, vec, Compare()),\n            FS(stdext::sorted_unique, vec.begin(), vec.end(), Compare()),\n            FS(stdext::sorted_unique, {1, 3, 5}, Compare()),\n        }) {\n            auto cmp = fs.key_comp();\n            assert(std::is_sorted(fs.begin(), fs.end(), cmp));\n        }\n    }\n}\n\ntemplate<class FS>\nstatic void SpecialMemberTest()\n{\n    static_assert(std::is_default_constructible<FS>::value, \"\");\n    static_assert(std::is_nothrow_move_constructible<FS>::value == std::is_nothrow_move_constructible<typename FS::container_type>::value, \"\");\n    static_assert(std::is_copy_constructible<FS>::value, \"\");\n    static_assert(std::is_copy_assignable<FS>::value, \"\");\n    static_assert(std::is_move_assignable<FS>::value, \"\");\n    static_assert(std::is_nothrow_destructible<FS>::value, \"\");\n}\n\n} // anonymous namespace\n\nvoid sg14_test::flat_set_test()\n{\n    AmbiguousEraseTest();\n    ExtractDoesntSwapTest();\n    MoveOperationsPilferOwnership();\n    ThrowingSwapDoesntBreakInvariants();\n    VectorBoolSanityTest();\n    VectorBoolEvilComparatorTest();\n\n    // Test the most basic flat_set.\n    {\n        using FS = stdext::flat_set<int>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n    }\n\n    // Test a custom comparator.\n    {\n        using FS = stdext::flat_set<int, std::greater<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n    }\n\n#if __cplusplus >= 201402L\n    // Test a transparent comparator.\n    {\n        using FS = stdext::flat_set<int, std::greater<>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n    }\n#endif\n\n    // Test a custom container.\n    {\n        using FS = stdext::flat_set<int, std::less<int>, std::deque<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n    }\n\n#if defined(__cpp_lib_memory_resource)\n    // Test a pmr container.\n    {\n        using FS = stdext::flat_set<int, std::less<int>, std::pmr::vector<int>>;\n        ConstructionTest<FS>();\n        SpecialMemberTest<FS>();\n    }\n#endif\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::flat_set_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/inplace_function_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include \"inplace_function.h\"\n#include <cassert>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <vector>\n\n#define EXPECT_EQ(val1, val2) assert(val1 == val2)\n#define EXPECT_TRUE(val) assert(val)\n#define EXPECT_FALSE(val) assert(!val)\n\nnamespace {\n\nstatic int copied, moved, called_with;\nstatic int expected;\n\nstruct Functor {\n    Functor() {}\n    Functor(const Functor&) { copied += 1; }\n    Functor(Functor&&) noexcept { moved += 1; }\n    void operator()(int i) { assert(i == expected); called_with = i; }\n};\n\nstruct ConstFunctor {\n    ConstFunctor() {}\n    ConstFunctor(const ConstFunctor&) { copied += 1; }\n    ConstFunctor(ConstFunctor&&) noexcept { moved += 1; }\n    void operator()(int i) const { assert(i == expected); called_with = i; }\n};\n\nvoid Foo(int i)\n{\n    assert(i == expected);\n    called_with = i;\n}\n\n} // anonymous namespace\n\nstatic std::string gLastS;\nstatic int gLastI = 0;\nstatic double gNextReturn = 0.0;\n\nstatic double GlobalFunction(const std::string& s, int i)\n{\n    gLastS = s;\n    gLastI = i;\n    return gNextReturn;\n}\n\nstatic void FunctionPointer()\n{\n    // Even compatible function pointers require an appropriate amount of \"storage\".\n    using CompatibleFunctionType = std::remove_reference_t<decltype(GlobalFunction)>;\n    stdext::inplace_function<CompatibleFunctionType, sizeof(CompatibleFunctionType*)> fun(&GlobalFunction);\n\n    EXPECT_TRUE(bool(fun));\n\n    gNextReturn = 7.77;\n\n    double r = fun(\"hello\", 42);\n\n    EXPECT_EQ(gNextReturn, r);\n    EXPECT_EQ(\"hello\", gLastS);\n    EXPECT_EQ(42, gLastI);\n}\n\nstatic void Lambda()\n{\n    stdext::inplace_function<double(int), 8> fun;\n    std::string closure(\"some closure\");\n    fun = [&closure](int x) { return GlobalFunction(closure, x); };\n\n    gNextReturn = 7.77;\n\n    double r = fun(42);\n\n    EXPECT_EQ(gNextReturn, r);\n    EXPECT_EQ(closure, gLastS);\n    EXPECT_EQ(42, gLastI);\n}\n\nstatic void Bind()\n{\n    stdext::inplace_function<double(int), 64> fun;\n    std::string closure(\"some closure\");\n    fun = std::bind(GlobalFunction, closure, std::placeholders::_1);\n\n    gNextReturn = 7.77;\n\n    double r = fun(42);\n\n    EXPECT_EQ(gNextReturn, r);\n    EXPECT_EQ(closure, gLastS);\n    EXPECT_EQ(42, gLastI);\n}\n\nstruct AnotherFunctor\n{\n    int mTotal = 0;\n    static int mDestructorCalls;\n    static int mConstructorCalls;\n    int operator()(int x) { mTotal += x; return mTotal; }\n\n    AnotherFunctor() { mConstructorCalls++; }\n    AnotherFunctor(AnotherFunctor&&) noexcept { mConstructorCalls++; }\n    AnotherFunctor(const AnotherFunctor&) { mConstructorCalls++; }\n    ~AnotherFunctor() { mDestructorCalls++; }\n};\n\nint AnotherFunctor::mDestructorCalls = 0;\nint AnotherFunctor::mConstructorCalls = 0;\n\nstatic void FunctorDestruction()\n{\n    AnotherFunctor::mDestructorCalls = 0;\n    AnotherFunctor::mConstructorCalls = 0;\n    {\n        AnotherFunctor ftor;\n        stdext::inplace_function<int(int), 4> fun(ftor);\n\n        int r1 = fun(1);\n        int r2 = fun(7);\n\n        EXPECT_EQ(1, r1);\n        EXPECT_EQ(8, r2);\n    }\n    EXPECT_EQ(AnotherFunctor::mDestructorCalls, AnotherFunctor::mConstructorCalls);\n\n    AnotherFunctor::mDestructorCalls = 0;\n    AnotherFunctor::mConstructorCalls = 0;\n    {\n        AnotherFunctor ftor;\n        stdext::inplace_function<int(int), 4> fun(ftor);\n        stdext::inplace_function<int(int), 4> fun2(fun);  // copy-ctor\n        stdext::inplace_function<int(int), 4> fun3(std::move(fun));  // move-ctor\n        fun3 = fun2;  // copy-asgn\n        fun3 = std::move(fun2);  // move-asgn\n    }\n    EXPECT_EQ(AnotherFunctor::mDestructorCalls, AnotherFunctor::mConstructorCalls);\n}\n\nstatic void Swapping()\n{\n    AnotherFunctor::mDestructorCalls = 0;\n    AnotherFunctor::mConstructorCalls = 0;\n    {\n        AnotherFunctor ftor;\n        auto lambda = [](int x){ return x + 10; };\n        stdext::inplace_function<int(int), 4> fun(ftor);\n        stdext::inplace_function<int(int), 4> fun2(lambda);\n\n        fun.swap(fun2);  // swap...\n        fun2.swap(fun);  // ...and swap back\n\n        int r1 = fun(1);\n        int r2 = fun(7);\n        EXPECT_EQ(1, r1);\n        EXPECT_EQ(8, r2);\n\n        int r3 = fun2(1);\n        int r4 = fun2(7);\n        EXPECT_EQ(11, r3);\n        EXPECT_EQ(17, r4);\n    }\n    EXPECT_EQ(AnotherFunctor::mDestructorCalls, AnotherFunctor::mConstructorCalls);\n}\n\nstatic void Copying()\n{\n    auto sptr = std::make_shared<int>(42);\n    EXPECT_EQ(1, sptr.use_count());\n\n    stdext::inplace_function<int(), 16> fun1 = [sptr]() { return *sptr; };\n    stdext::inplace_function<int(), 16> fun2;\n\n    EXPECT_EQ(2, sptr.use_count());\n    EXPECT_TRUE(bool(fun1));\n    EXPECT_FALSE(bool(fun2));\n\n    fun2 = fun1;\n    EXPECT_EQ(3, sptr.use_count());\n    EXPECT_TRUE(bool(fun1));\n    EXPECT_TRUE(bool(fun2));\n\n    // this should call destructor on existing functor\n    fun1 = nullptr;\n    EXPECT_EQ(2, sptr.use_count());\n    EXPECT_FALSE(bool(fun1));\n    EXPECT_TRUE(bool(fun2));\n}\n\nstatic void ContainingStdFunction()\n{\n    // build a big closure, bigger than 32 bytes\n    uint64_t offset1 = 1234;\n    uint64_t offset2 = 77;\n    uint64_t offset3 = 666;\n    std::string str1 = \"12345\";\n\n    std::function<int(const std::string&)> stdfun\n                    = [offset1, offset2, offset3, str1](const std::string& str)\n    {\n        return int(offset1 + offset2 + offset3 + str1.length() + str.length());\n    };\n\n    stdext::inplace_function<int(const std::string&), 64> fun = stdfun;\n\n    int r = fun(\"123\");\n    EXPECT_EQ(r, int(offset1+offset2+offset3+str1.length()+3));\n}\n\nstatic void SimilarTypeCopy()\n{\n    auto sptr = std::make_shared<int>(42);\n    EXPECT_EQ(1, sptr.use_count());\n\n    stdext::inplace_function<int(), 16> fun1 = [sptr]() { return *sptr; };\n    stdext::inplace_function<int(), 17> fun2(fun1); // fun1 is bigger than 17, but we should be smart about it\n    stdext::inplace_function<int(), 18> fun3;\n\n    EXPECT_EQ(3, sptr.use_count());\n    EXPECT_FALSE(fun3);\n    fun3 = fun2;\n    EXPECT_EQ(4, sptr.use_count());\n    EXPECT_TRUE(bool(fun2));\n    EXPECT_TRUE(bool(fun3));\n\n    fun1 = nullptr;\n    fun2 = nullptr;\n    EXPECT_EQ(2, sptr.use_count());\n    fun3 = nullptr;\n    EXPECT_EQ(1, sptr.use_count());\n\n    stdext::inplace_function<int(), 17> fun4;\n    fun4 = fun1; // fun1 is bigger than 17, but we should be smart about it\n}\n\nstatic void AssignmentDifferentFunctor()\n{\n    int calls = 0;\n    stdext::inplace_function<int(int,int), 16> add = [&calls] (int a, int b) { ++calls; return a+b; };\n    stdext::inplace_function<int(int,int), 16> mul = [&calls] (int a, int b) { ++calls; return a*b; };\n\n    int r1 = add(3, 5);\n    EXPECT_EQ(8, r1);\n\n    int r2 = mul(2, 5);\n    EXPECT_EQ(10, r2);\n\n    EXPECT_EQ(2, calls);\n\n    add = mul;\n\n    int r3 = add(3, 5);\n    EXPECT_EQ(15, r3);\n\n    int r4 = mul(2, 5);\n    EXPECT_EQ(10, r4);\n\n    EXPECT_EQ(4, calls);\n}\n\nstruct ThrowingFunctor {\n    static int countdown;\n    static int constructed;\n    static int destructed;\n    static int called;\n    static void reset(int k) {\n        countdown = k;\n        constructed = 0;\n        destructed = 0;\n        called = 0;\n    }\n    static void check_countdown() {\n        if (countdown > 0 && --countdown == 0) {\n            throw 42;\n        }\n    }\n    ThrowingFunctor() { check_countdown(); ++constructed; }\n    ThrowingFunctor(const ThrowingFunctor&) {\n        check_countdown();\n        ++constructed;\n    }\n    ThrowingFunctor(ThrowingFunctor&&) noexcept { ++constructed; }\n    ThrowingFunctor& operator=(const ThrowingFunctor&) = delete;\n    ThrowingFunctor& operator=(ThrowingFunctor&&) = delete;\n    ~ThrowingFunctor() noexcept { ++destructed; }\n    void operator()() const { ++called; }\n};\nint ThrowingFunctor::countdown = 0;\nint ThrowingFunctor::constructed = 0;\nint ThrowingFunctor::destructed = 0;\nint ThrowingFunctor::called = 0;\n\nstatic void test_exception_safety()\n{\n    using IPF = stdext::inplace_function<void(), sizeof(ThrowingFunctor)>;\n    ThrowingFunctor tf;\n    EXPECT_EQ(ThrowingFunctor::constructed, 1);\n    EXPECT_EQ(ThrowingFunctor::destructed, 0);\n    EXPECT_EQ(ThrowingFunctor::called, 0);\n    bool caught;\n\n    // Copy-construction from a ThrowingFunctor might throw.\n    try { tf.reset(1); caught = false; IPF a(tf); } catch (int) { caught = true; }\n    EXPECT_TRUE((caught) && (tf.countdown == 0) && (tf.constructed == 0) && (tf.destructed == 0));\n    try { tf.reset(2); caught = false; IPF a(tf); } catch (int) { caught = true; }\n    EXPECT_TRUE((!caught) && (tf.countdown == 1) && (tf.constructed == 1) && (tf.destructed == 1));\n\n    // Copy-construction from an IPF (containing a ThrowingFunctor) might throw.\n    try { tf.reset(2); caught = false; IPF a(tf); IPF b(a); } catch (int) { caught = true; }\n    EXPECT_TRUE((caught) && (tf.countdown == 0) && (tf.constructed == 1) && (tf.destructed == 1));\n    try { tf.reset(3); caught = false; IPF a(tf); IPF b(a); } catch (int) { caught = true; }\n    EXPECT_TRUE((!caught) && (tf.countdown == 1) && (tf.constructed == 2) && (tf.destructed == 2));\n\n    // Move-construction and destruction should be assumed not to throw.\n    try { tf.reset(1); caught = false; IPF a(std::move(tf)); IPF b(std::move(a)); } catch (int) { caught = true; }\n    EXPECT_TRUE((!caught) && (tf.countdown == 1) && (tf.constructed == 2) && (tf.destructed == 2));\n\n    // The assignment operators are implemented as \"construct an IPF, then move from it\"; so, one copy and one move of the ThrowingFunctor.\n    try { tf.reset(1); caught = false; IPF a; a = tf; } catch (int) { caught = true; }\n    EXPECT_TRUE((caught) && (tf.countdown == 0) && (tf.constructed == 0) && (tf.destructed == 0));\n    try { tf.reset(2); caught = false; IPF a; a = tf; } catch (int) { caught = true; }\n    EXPECT_TRUE((!caught) && (tf.countdown == 1) && (tf.constructed == 2) && (tf.destructed == 2));\n\n    // The assignment operators are implemented as \"construct an IPF, then move from it\"; so, two moves of the ThrowingFunctor.\n    try { tf.reset(1); caught = false; IPF a; a = std::move(tf); } catch (int) { caught = true; }\n    EXPECT_TRUE((!caught) && (tf.countdown == 1) && (tf.constructed == 2) && (tf.destructed == 2));\n\n    try { tf.reset(1); caught = false; IPF a; IPF b(tf); a = b; } catch (int) { caught = true; }\n    EXPECT_TRUE((caught) && (tf.countdown == 0) && (tf.constructed == 0) && (tf.destructed == 0));\n    try { tf.reset(2); caught = false; IPF a; IPF b(tf); a = b; } catch (int) { caught = true; }\n    EXPECT_TRUE((caught) && (tf.countdown == 0) && (tf.constructed == 1) && (tf.destructed == 1));\n}\n\ntemplate<size_t Cap>\nconstexpr size_t expected_alignment_for_capacity()\n{\n    constexpr size_t alignof_ptr = std::alignment_of<void*>::value;\n    constexpr size_t alignof_cap = std::alignment_of<std::aligned_storage_t<Cap>>::value;\n#define MIN(a,b) (a < b ? a : b)\n#define MAX(a,b) (a > b ? a : b)\n    return MAX(MIN(Cap, alignof_cap), alignof_ptr);\n#undef MAX\n#undef MIN\n}\n\nstatic void test_struct_layout()\n{\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 1> >::value == expected_alignment_for_capacity<1>(), \"\");\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 2> >::value == expected_alignment_for_capacity<2>(), \"\");\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 4> >::value == expected_alignment_for_capacity<4>(), \"\");\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 8> >::value == expected_alignment_for_capacity<8>(), \"\");\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 16> >::value == expected_alignment_for_capacity<16>(), \"\");\n    static_assert(std::alignment_of< stdext::inplace_function<void(int), 32> >::value == expected_alignment_for_capacity<32>(), \"\");\n    static_assert(sizeof( stdext::inplace_function<void(int), sizeof(void*)> ) == 2 * sizeof(void*), \"\");\n}\n\nstatic void test_nullptr()\n{\n    using IPF = stdext::inplace_function<void()>;\n    auto nil = nullptr;\n    const auto cnil = nullptr;\n\n    IPF f;                    assert(! bool(f));\n    f = nullptr;              assert(! bool(f));\n    f = IPF(nullptr);         assert(! bool(f));\n    f = IPF();                assert(! bool(f));\n    f = IPF{};                assert(! bool(f));\n    f = {};                   assert(! bool(f));\n    f = nil;                  assert(! bool(f));\n    f = IPF(nil);             assert(! bool(f));\n    f = IPF(std::move(nil));  assert(! bool(f));\n    f = cnil;                 assert(! bool(f));\n    f = IPF(cnil);            assert(! bool(f));\n    f = IPF(std::move(cnil)); assert(! bool(f));\n}\n\nstruct oon_functor {\n    int dummy;\n\n    oon_functor(int i) : dummy(i) {}\n    int operator()(int i) { return i + dummy; }\n\n    void *operator new (size_t, void *p) {\n        EXPECT_TRUE(false);  // class-specific \"new\" should not be called\n        return p;\n    }\n};\n\nstatic void test_overloaded_operator_new()\n{\n    using IPF = stdext::inplace_function<int(int), 8>;\n    oon_functor oon(42);\n    IPF fun = oon;\n    IPF fun2;\n    fun2 = oon;\n    fun = fun2;\n    EXPECT_EQ(43, fun(1));\n}\n\nstatic void test_move_construction_is_noexcept()\n{\n    using IPF = stdext::inplace_function<void(int), sizeof(Functor)>;\n    std::vector<IPF> vec;\n    vec.push_back(Functor());\n    copied = 0;\n    moved = 0;\n    vec.reserve(vec.capacity() + 1);\n    EXPECT_EQ(0, copied);\n    EXPECT_EQ(1, moved);\n}\n\nstatic void test_move_construction_from_smaller_buffer_is_noexcept()\n{\n    using IPF32 = stdext::inplace_function<void(int), 32>;\n    using IPF40 = stdext::inplace_function<void(int), 40>;\n    static_assert(std::is_nothrow_constructible<IPF32, IPF32&&>::value, \"\");\n    static_assert(std::is_nothrow_assignable<IPF32, IPF32&&>::value, \"\");\n    static_assert(std::is_nothrow_constructible<IPF40, IPF32&&>::value, \"\");\n    static_assert(std::is_nothrow_assignable<IPF40, IPF32&&>::value, \"\");\n}\n\n// https://bugs.llvm.org/show_bug.cgi?id=32072\nstruct test_bug_32072_C;\nstruct test_bug_32072 {\n    stdext::inplace_function<test_bug_32072_C()> m;\n};\nstatic_assert(std::is_copy_constructible<test_bug_32072>::value, \"\");\nstatic_assert(std::is_nothrow_move_constructible<test_bug_32072>::value, \"\");\n\nstatic void RvalueRefParameter()\n{\n    stdext::inplace_function<void(std::unique_ptr<int>&&)> f;\n    f = [](std::unique_ptr<int>) {};\n    f = [](std::unique_ptr<int>&&) {};\n    f = [](const std::unique_ptr<int>&) {};\n    f(std::make_unique<int>(42));\n    stdext::inplace_function<void(std::unique_ptr<int>)> g;\n    g = [](std::unique_ptr<int>) {};\n    g = [](std::unique_ptr<int>&&) {};\n    g = [](const std::unique_ptr<int>&) {};\n    g(std::make_unique<int>(42));\n}\n\nstatic void test_is_convertible()\n{\n    static_assert(std::is_convertible<int(&)(), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(std::is_convertible<int(*)(), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(std::is_convertible<int(*&)(), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(std::is_convertible<int(*&&)(), stdext::inplace_function<int()>>::value, \"\");\n}\n\nstatic void test_convertibility_with_qualified_call_operators()\n{\n    struct Callable { void operator()() {} };\n    struct LvalueOnlyCallable { void operator()() & {} };\n    struct RvalueOnlyCallable { void operator()() && {} };\n    struct ConstCallable { void operator()() const {} };\n    struct ConstOnlyCallable { void operator()() const {} void operator()() = delete; };\n    struct NonconstOnlyCallable { void operator()() {} void operator()() const = delete; };\n    struct LvalueConstCallable { void operator()() const & {} };\n    struct NoexceptCallable { void operator()() noexcept {} };\n    static_assert(std::is_convertible<Callable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(std::is_convertible<LvalueOnlyCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(!std::is_convertible<RvalueOnlyCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(std::is_convertible<ConstCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(!std::is_convertible<ConstOnlyCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(std::is_convertible<NonconstOnlyCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(std::is_convertible<LvalueConstCallable, stdext::inplace_function<void()>>::value, \"\");\n    static_assert(std::is_convertible<NoexceptCallable, stdext::inplace_function<void()>>::value, \"\");\n}\n\nstatic void test_convertibility_with_lambdas()\n{\n    struct NoDefaultCtor {\n        int val;\n        explicit NoDefaultCtor(int v) : val{v} {}\n    };\n\n    const auto a = []() -> int { return 3; };\n    static_assert(std::is_convertible<decltype(a), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(a), stdext::inplace_function<int(int)>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(a), stdext::inplace_function<void(int&)>>::value, \"\");\n\n    const auto b = [](int&) -> void {};\n    static_assert(std::is_convertible<decltype(b), stdext::inplace_function<void(int&)>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(b), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(b), stdext::inplace_function<int(int)>>::value, \"\");\n\n    const auto c = [](int, NoDefaultCtor) -> int { return 3; };\n    static_assert(std::is_convertible<decltype(c), stdext::inplace_function<void(int, NoDefaultCtor)>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(c), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(c), stdext::inplace_function<int(int)>>::value, \"\");\n\n    const auto d = []() -> void {};\n    static_assert(std::is_convertible<decltype(d), stdext::inplace_function<void()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(d), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(d), stdext::inplace_function<int(int)>>::value, \"\");\n\n    static_assert(std::is_convertible<int(), stdext::inplace_function<const int&()>>::value, \"\");\n    static_assert(std::is_convertible<int(*)(), stdext::inplace_function<const int&()>>::value, \"\");\n\n    // Same as a, but not const.\n    auto e = []() -> int { return 3; };\n    static_assert(std::is_convertible<decltype(e), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(e), stdext::inplace_function<int(int)>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(e), stdext::inplace_function<void(int&)>>::value, \"\");\n\n    // Same as a, but not const and mutable.\n    auto f = []() mutable -> int { return 3; };\n    static_assert(std::is_convertible<decltype(f), stdext::inplace_function<int()>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(f), stdext::inplace_function<int(int)>>::value, \"\");\n    static_assert(!std::is_convertible<decltype(f), stdext::inplace_function<void(int&)>>::value, \"\");\n}\n\nnamespace {\nstruct InstrumentedCopyConstructor {\n    static int copies;\n    static int moves;\n    InstrumentedCopyConstructor() = default;\n    InstrumentedCopyConstructor(const InstrumentedCopyConstructor&) {\n        copies += 1;\n    }\n    InstrumentedCopyConstructor(InstrumentedCopyConstructor&&) noexcept {\n        moves += 1;\n    }\n};\nint InstrumentedCopyConstructor::copies = 0;\nint InstrumentedCopyConstructor::moves = 0;\n} // anonymous namespace\n\nstatic void test_return_by_move()\n{\n    using IPF20 = stdext::inplace_function<void(), 20>;\n    using IPF40 = stdext::inplace_function<void(), 40>;\n    static_assert(std::is_convertible<IPF20, IPF40>::value, \"\");\n    static_assert(std::is_convertible<IPF20&, IPF40>::value, \"\");\n    static_assert(std::is_convertible<IPF20&&, IPF40>::value, \"\");\n    static_assert(std::is_convertible<const IPF20&, IPF40>::value, \"\");\n    static_assert(std::is_convertible<const IPF20&&, IPF40>::value, \"\");\n\n    auto foo = []() -> IPF40 {\n        InstrumentedCopyConstructor cc;\n        InstrumentedCopyConstructor::copies = 0;\n        InstrumentedCopyConstructor::moves = 0;\n        IPF20 f = [cc]() { };\n        assert(InstrumentedCopyConstructor::copies == 1);\n        assert(InstrumentedCopyConstructor::moves == 1);\n        InstrumentedCopyConstructor::copies = 0;\n        InstrumentedCopyConstructor::moves = 0;\n        return f;\n    };\n    IPF40 f = foo();\n    assert(InstrumentedCopyConstructor::copies == 0);\n    assert(InstrumentedCopyConstructor::moves == 1);\n}\n\nstatic void test_is_invocable()\n{\n    using C_Int1 = int();\n    using C_Int2 = int(int);\n    using C_Void = void(int&);\n\n    using stdext::inplace_function_detail::is_invocable_r;\n\n    static_assert(is_invocable_r<int, C_Int1>::value, \"\");\n    static_assert(! is_invocable_r<int, C_Int2>::value, \"\");\n    static_assert(! is_invocable_r<int, C_Void>::value, \"\");\n\n    static_assert(is_invocable_r<int, C_Int2, int>::value, \"\");\n    static_assert(! is_invocable_r<int, C_Int1, int>::value, \"\");\n    static_assert(! is_invocable_r<int, C_Void, int>::value, \"\");\n\n    static_assert(is_invocable_r<void, C_Void, int&>::value, \"\");\n    static_assert(! is_invocable_r<void, C_Int1, int&>::value, \"\");\n\n    // Testing widening and narrowing conversions, and the \"conversion\" to void.\n    static_assert(is_invocable_r<void, C_Int1>::value, \"\");\n    static_assert(is_invocable_r<long, C_Int1>::value, \"\");\n    static_assert(is_invocable_r<char, C_Int1>::value, \"\");\n\n    // Testing the conversion from void to int, which should definitely not be allowed.\n    static_assert(! is_invocable_r<int, C_Void, int&>::value, \"\");\n\n    // cppreference:\n    // > Determines whether Fn can be invoked with the arguments ArgTypes...\n    // > to yield a result that is convertible to R.\n    //\n    // void is treated specially because a functions return value can be ignored.\n    static_assert(is_invocable_r<void, C_Int2, int&>::value, \"\");\n    static_assert(is_invocable_r<const void, C_Int2, int&>::value, \"\");\n\n    // Regression tests for both is_invocable and is_convertible.\n    static_assert(is_invocable_r<const int&, int()>::value, \"\");\n    static_assert(is_invocable_r<const int&, int(*)()>::value, \"\");\n}\n\nstatic int overloaded_function(stdext::inplace_function<int()>) { return 1; }\nstatic int overloaded_function(stdext::inplace_function<int(int)>) { return 2; }\nstatic void test_overloading_on_arity()\n{\n    EXPECT_EQ(overloaded_function([]() { return 0; }), 1);\n    EXPECT_EQ(overloaded_function([](int) { return 0; }), 2);\n}\n\nstatic int overloaded_function2(stdext::inplace_function<int(int)>) { return 1; }\nstatic int overloaded_function2(stdext::inplace_function<int(int*)>) { return 2; }\nstatic void test_overloading_on_parameter_type()\n{\n    EXPECT_EQ(overloaded_function2([](int) { return 0; }), 1);\n    EXPECT_EQ(overloaded_function2([](int*) { return 0; }), 2);\n}\n\nstatic int overloaded_function3(stdext::inplace_function<int(int)>) { return 1; }\nstatic int overloaded_function3(stdext::inplace_function<int*(int)>) { return 2; }\nstatic void test_overloading_on_return_type()\n{\n    EXPECT_EQ(overloaded_function3([](int) { return 0; }), 1);\n    EXPECT_EQ(overloaded_function3([](int) { return nullptr; }), 2);\n}\n\nvoid sg14_test::inplace_function_test()\n{\n    // first set of tests (from Optiver)\n    AssignmentDifferentFunctor();\n    FunctionPointer();\n    Lambda();\n    Bind();\n    Swapping();\n    Copying();\n    ContainingStdFunction();\n    SimilarTypeCopy();\n    FunctorDestruction();\n    RvalueRefParameter();\n\n    // second set of tests\n    using IPF = stdext::inplace_function<void(int)>;\n    static_assert(std::is_nothrow_default_constructible<IPF>::value, \"\");\n    static_assert(std::is_copy_constructible<IPF>::value, \"\");\n    static_assert(std::is_move_constructible<IPF>::value, \"\");\n    static_assert(std::is_copy_assignable<IPF>::value, \"\");\n    static_assert(std::is_move_assignable<IPF>::value, \"\");\n#if __cplusplus >= 201703L\n    static_assert(std::is_swappable<IPF&>::value, \"\");\n    static_assert(std::is_invocable<const IPF&, int>::value, \"\");\n    static_assert(std::is_invocable_r<void, const IPF&, int>::value, \"\");\n#endif\n    static_assert(std::is_nothrow_destructible<IPF>::value, \"\");\n\n    test_struct_layout();\n\n    IPF func;\n    assert(!func);\n    assert(!bool(func));\n    assert(func == nullptr);\n    assert(!(func != nullptr));\n    expected = 0; try { func(42); } catch (std::bad_function_call&) { expected = 1; } assert(expected == 1);\n\n    func = Foo;\n    assert(!!func);\n    assert(func);\n    assert(!(func == nullptr));\n    assert(func != nullptr);\n    called_with = 0; expected = 42; func(42); assert(called_with == 42);\n\n    func = nullptr;\n    assert(!func);\n    assert(!bool(func));\n    assert(func == nullptr);\n    assert(!(func != nullptr));\n    expected = 0; try { func(42); } catch (std::bad_function_call&) { expected = 1; } assert(expected == 1);\n\n    using IPF40 = stdext::inplace_function<void(int), 40>; // the default is 32\n    static_assert(std::is_constructible<IPF40, const IPF&>::value, \"\");\n    static_assert(std::is_constructible<IPF40, IPF&&>::value, \"\");  // TODO: nothrow\n    static_assert(std::is_assignable<IPF40&, const IPF&>::value, \"\");\n    static_assert(std::is_assignable<IPF40&, IPF&&>::value, \"\");  // TODO: nothrow\n    //static_assert(!std::is_assignable<IPF&, const IPF40&>::value, \"\");\n    //static_assert(!std::is_assignable<IPF&, IPF40&&>::value, \"\");\n#if __cplusplus >= 201703L\n    static_assert(!std::is_swappable_with<IPF40&, IPF&>::value, \"\");\n    static_assert(!std::is_swappable_with<IPF&, IPF40&>::value, \"\");\n#endif\n    static_assert(std::is_nothrow_destructible<IPF40>::value, \"\");\n\n    IPF40 func40;\n    assert(!func40);\n    assert(!bool(func40));\n    assert(func40 == nullptr);\n    assert(!(func40 != nullptr));\n    expected = 0; try { func40(42); } catch (std::bad_function_call&) { expected = 1; } assert(expected == 1);\n\n    func = nullptr;\n    func40 = func;\n    assert(!func40);\n    assert(!bool(func40));\n    assert(func40 == nullptr);\n    assert(!(func40 != nullptr));\n    expected = 0; try { func40(42); } catch (std::bad_function_call&) { expected = 1; } assert(expected == 1);\n\n    test_exception_safety();\n    test_nullptr();\n    test_overloaded_operator_new();\n    test_move_construction_is_noexcept();\n    test_move_construction_from_smaller_buffer_is_noexcept();\n    test_is_convertible();\n    test_convertibility_with_qualified_call_operators();\n    test_convertibility_with_lambdas();\n    test_return_by_move();\n    test_is_invocable();\n    test_overloading_on_arity();\n    test_overloading_on_parameter_type();\n    test_overloading_on_return_type();\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::inplace_function_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/main.cpp",
    "content": "#if defined(_MSC_VER)\n#include <SDKDDKVer.h>\n#endif\n\n#include <stdio.h>\n\n#include \"SG14_test.h\"\n\nint main(int, char *[])\n{\n    sg14_test::flat_map_test();\n    sg14_test::flat_set_test();\n    sg14_test::inplace_function_test();\n    sg14_test::plf_colony_test();\n    sg14_test::ring_test();\n    sg14_test::slot_map_test();\n    sg14_test::uninitialized_test();\n    sg14_test::unstable_remove_test();\n\n    puts(\"tests completed\");\n\n    return 0;\n}\n"
  },
  {
    "path": "SG14_test/plf_colony_test.cpp",
    "content": "#define PLF_COLONY_TEST_DEBUG\r\n\r\n#if defined(_MSC_VER)\r\n\t#if _MSC_VER >= 1600\r\n\t\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t#endif\r\n\t#if _MSC_VER >= 1700\r\n\t\t#define PLF_TEST_TYPE_TRAITS_SUPPORT\r\n\t#endif\r\n\t#if _MSC_VER >= 1800\r\n\t\t#define PLF_TEST_VARIADICS_SUPPORT // Variadics, in this context, means both variadic templates and variadic macros are supported\r\n\t\t#define PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t#endif\r\n\r\n\t#if defined(_MSVC_LANG) && (_MSVC_LANG > 201703L) && _MSC_VER >= 1923\r\n\t\t#define PLF_TEST_CPP20_SUPPORT\r\n\t#endif\r\n#elif defined(__cplusplus) && __cplusplus >= 201103L // C++11 support, at least\r\n\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\r\n\t#if defined(__GNUC__) && defined(__GNUC_MINOR__) && !defined(__clang__) // If compiler is GCC/G++\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4 // 4.2 and below do not support variadic templates\r\n\t\t\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#define PLF_TEST_VARIADICS_SUPPORT\r\n\t\t#endif\r\n\t\t#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 // 4.3 and below do not support initializer lists\r\n\t\t\t#define PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GNUC__ >= 5 // GCC v4.9 and below do not support std::is_trivially_copyable\r\n\t\t\t#define PLF_TEST_TYPE_TRAITS_SUPPORT\r\n\t\t#endif\r\n\t#elif defined(__clang__) && !defined(__GLIBCXX__) && !defined(_LIBCPP_CXX03_LANG)\r\n\t\t#if __clang_major__ >= 3 // clang versions < 3 don't support __has_feature() or traits\r\n\t\t\t#define PLF_TEST_TYPE_TRAITS_SUPPORT\r\n\r\n\t\t\t#if __has_feature(cxx_rvalue_references) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES)\r\n\t\t\t\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#endif\r\n\t\t\t#if __has_feature(cxx_variadic_templates) && !defined(_LIBCPP_HAS_NO_VARIADICS)\r\n\t\t\t\t#define PLF_TEST_VARIADICS_SUPPORT\r\n\t\t\t#endif\r\n\t\t\t#if (__clang_major__ == 3 && __clang_minor__ >= 1) || __clang_major__ > 3\r\n\t\t\t\t#define PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t\t\t#endif\r\n\t\t#endif\r\n\t#elif defined(__GLIBCXX__)\r\n\t\t#if __GLIBCXX__ >= 20080606\r\n\t\t\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t#define PLF_TEST_VARIADICS_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20090421\r\n\t\t\t#define PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t\t#endif\r\n\t\t#if __GLIBCXX__ >= 20150422\r\n\t\t\t#define PLF_TEST_TYPE_TRAITS_SUPPORT\r\n\t\t#endif\r\n\t#elif !(defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) || defined(_LIBCPP_HAS_NO_VARIADICS))\r\n\t\t// Assume full support for other compilers and standard libraries\r\n\t\t#define PLF_TEST_VARIADICS_SUPPORT\r\n\t\t#define PLF_TEST_TYPE_TRAITS_SUPPORT\r\n\t\t#define PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t\t#define PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t#endif\r\n\r\n\t#if __cplusplus > 201703L && ((defined(__clang__) && (__clang_major__ >= 10)) || (defined(__GNUC__) && __GNUC__ >= 10) || (!defined(__clang__) && !defined(__GNUC__))) // assume correct C++20 implementation for other compilers\r\n\t\t#define PLF_TEST_CPP20_SUPPORT\r\n\t#endif\r\n#endif\r\n\r\n\r\n\r\n#include <numeric> // std::accumulate\r\n#include <algorithm> // std::find\r\n#include <cstdio> // log redirection, printf\r\n#include <cstdlib> // abort\r\n#include <functional> // std::greater\r\n#include <vector> // range-insert testing\r\n\r\n#ifdef PLF_TEST_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t#include <utility> // std::move\r\n#endif\r\n\r\n#include \"plf_colony.h\"\r\n\r\n\r\nnamespace\r\n{\r\n\r\n\tinline void failpass(const char* test_type, bool condition)\r\n\t{\r\n\t\tif (!condition)\r\n\t\t{\r\n\t\t\tprintf(\"%s: Fail\\n\", test_type);\r\n\t\t\tgetchar();\r\n\t\t\tabort();\r\n\t\t}\r\n\t}\r\n\r\n\tvoid message(const char *)\r\n\t{\r\n\t}\r\n\r\n\r\n\tvoid title1(const char*)\r\n\t{\r\n\t}\r\n\r\n\tvoid title2(const char*)\r\n\t{\r\n\t}\r\n\r\n\r\n\r\n#ifdef PLF_TEST_VARIADICS_SUPPORT\r\n\tstruct perfect_forwarding_test\r\n\t{\r\n\t\tconst bool success;\r\n\r\n\t\tperfect_forwarding_test(int&& /*perfect1*/, int& perfect2)\r\n\t\t\t: success(true)\r\n\t\t{\r\n\t\t\tperfect2 = 1;\r\n\t\t}\r\n\r\n\t\ttemplate <typename T, typename U>\r\n\t\tperfect_forwarding_test(T&& /*imperfect1*/, U&& /*imperfect2*/)\r\n\t\t\t: success(false)\r\n\t\t{}\r\n\t};\r\n\r\n\r\n\r\n\tstruct small_struct\r\n\t{\r\n\t\tdouble *empty_field_1;\r\n\t\tdouble unused_number;\r\n\t\tunsigned int empty_field2;\r\n\t\tdouble *empty_field_3;\r\n\t\tint number;\r\n\t\tunsigned int empty_field4;\r\n\r\n\t\tsmall_struct(const int num) : number(num) {};\r\n\t};\r\n\r\n\r\n\r\n\tclass non_copyable_type\r\n\t{\r\n\tprivate:\r\n\t\tint i;\r\n\t\tnon_copyable_type(const non_copyable_type &); // non construction-copyable\r\n\t\tnon_copyable_type& operator=(const non_copyable_type &); // non copyable\r\n\tpublic:\r\n\t\tnon_copyable_type(int a) : i(a) {}\r\n\t};\r\n\r\n#endif\r\n\r\n\r\n\r\n\r\n\tint global_counter = 0;\r\n\r\n\tstruct small_struct_non_trivial\r\n\t{\r\n\t\tdouble* empty_field_1;\r\n\t\tdouble unused_number;\r\n\t\tunsigned int empty_field2;\r\n\t\tdouble* empty_field_3;\r\n\t\tint number;\r\n\t\tunsigned int empty_field4;\r\n\r\n\t\tsmall_struct_non_trivial(const int num) : number(num) {};\r\n\t\t~small_struct_non_trivial() { ++global_counter; };\r\n\t};\r\n}\r\n\r\n\r\n// xor_shift128++ generator substituted for pre-C++11 compilers (since C++03 doesn't have guaranteed cross-compiler 64-bit unsigned ints).\r\n// Based on https://codingforspeed.com/using-faster-psudo-random-generator-xorshift/\r\n\r\nnamespace plf\r\n{\r\n\r\n// unsigned long is at least 32 bits in C++ - unsigned int is only guaranteed to be at least 16 bits:\r\nunsigned long xorand_nums[4] = {123456789, 362436069, 521288629, 88675123};\r\n\r\n\r\nunsigned int rand()\r\n{\r\n\tconst unsigned long temp = xorand_nums[0] ^ (xorand_nums[0] << 11);\r\n\r\n\t// Rotate the static values ([3] rotation in return statement):\r\n\txorand_nums[0] = xorand_nums[1];\r\n\txorand_nums[1] = xorand_nums[2];\r\n\txorand_nums[2] = xorand_nums[3];\r\n\r\n\treturn static_cast<unsigned int>(xorand_nums[3] = xorand_nums[3] ^ (xorand_nums[3] >> 19) ^ (temp ^ (temp >> 8)));\r\n}\r\n\r\n}\r\n\r\n\r\n\r\nnamespace sg14_test\r\n{\r\n\r\nvoid plf_colony_test()\r\n{\r\n\tusing namespace std;\r\n\tusing namespace plf;\r\n\r\n\r\n\tunsigned int looper = 0;\r\n\r\n\twhile (++looper != 25)\r\n\t{\r\n\t\t{\r\n\t\t\ttitle1(\"Colony\");\r\n\t\t\ttitle2(\"Test Basics\");\r\n\r\n\t\t\tcolony<int *> p_colony;\r\n\r\n\t\t\tfailpass(\"Colony empty\", p_colony.empty());\r\n\r\n\t\t\tint ten = 10;\r\n\t\t\tp_colony.insert(&ten);\r\n\r\n\t\t\tfailpass(\"Colony not-empty\", !p_colony.empty());\r\n\r\n\t\t\ttitle2(\"Iterator tests\");\r\n\r\n\t\t\tfailpass(\"Begin() working\", **p_colony.begin() == 10);\r\n\t\t\tfailpass(\"End() working\", p_colony.begin() != p_colony.end());\r\n\r\n\r\n\t\t\tp_colony.clear();\r\n\r\n\t\t\tfailpass(\"Begin = End after clear\", p_colony.begin() == p_colony.end());\r\n\r\n\t\t\tint twenty = 20;\r\n\r\n\t\t\tfor (unsigned int temp = 0; temp != 200; ++temp)\r\n\t\t\t{\r\n\t\t\t\tp_colony.insert(&ten);\r\n\t\t\t\tp_colony.insert(&twenty);\r\n\t\t\t}\r\n\r\n\t\t\tint total = 0, numtotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::iterator the_iterator = p_colony.begin(); the_iterator != p_colony.end(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tnumtotal += **the_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Iteration count test\", total == 400);\r\n\t\t\tfailpass(\"Iterator access test\", numtotal == 6000);\r\n\r\n\t\t\tcolony<int *>::iterator plus_twenty = p_colony.begin();\r\n\t\t\tadvance(plus_twenty, 20);\r\n\t\t\tcolony<int *>::iterator plus_two_hundred = p_colony.begin();\r\n\t\t\tadvance(plus_two_hundred, 200);\r\n\r\n\t\t\tfailpass(\"Iterator + distance test\", distance(p_colony.begin(), plus_twenty) == 20);\r\n\t\t\tfailpass(\"Iterator - distance test\", distance(plus_two_hundred, p_colony.begin()) == -200);\r\n\r\n\t\t\tcolony<int *>::iterator next_iterator = next(p_colony.begin(), 5);\r\n\t\t\tcolony<int *>::const_iterator prev_iterator = prev(p_colony.cend(), 300);\r\n\r\n\t\t\tfailpass(\"Iterator next test\", distance(p_colony.begin(), next_iterator) == 5);\r\n\t\t\tfailpass(\"Const iterator prev test\", distance(p_colony.cend(), prev_iterator) == -300);\r\n\r\n\t\t\t#if defined(__cplusplus) && __cplusplus >= 201402L\r\n\t\t\t\tcolony<int *>::iterator prev_iterator2 = prev(p_colony.end(), 300);\r\n\t\t\t\tfailpass(\"Iterator/Const iterator equality operator test\", prev_iterator == prev_iterator2);\r\n\t\t\t#endif\r\n\r\n\t\t\tprev_iterator = p_colony.begin();\r\n\t\t\tadvance(prev_iterator, 5);\r\n\t\t\tfailpass(\"Iterator/Const iterator equality operator test 2\", prev_iterator == next_iterator);\r\n\r\n\t\t\tcolony<int *> p_colony2;\r\n\t\t\tp_colony2 = p_colony;\r\n\t\t\tcolony<int *> p_colony3(p_colony);\r\n\t\t\tcolony<int *> p_colony4(p_colony2, p_colony2.get_allocator());\r\n\r\n\t\t\tcolony<int *>::iterator it1 = p_colony.begin();\r\n\t\t\tcolony<int *>::const_iterator cit(it1);\r\n\r\n\t\t\tfailpass(\"Copy test\", p_colony2.size() == 400);\r\n\t\t\tfailpass(\"Copy construct test\", p_colony3.size() == 400);\r\n\t\t\tfailpass(\"Allocator-extended copy construct test\", p_colony4.size() == 400);\r\n\r\n\r\n\t\t\tfailpass(\"Equality operator test\", p_colony == p_colony2);\r\n\t\t\tfailpass(\"Equality operator test 2\", p_colony2 == p_colony3);\r\n\r\n\t\t\tp_colony2.insert(&ten);\r\n\r\n\t\t\tfailpass(\"Inequality operator test\", p_colony2 != p_colony3);\r\n\r\n\t\t\tnumtotal = 0;\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int *>::reverse_iterator the_iterator = p_colony.rbegin(); the_iterator != p_colony.rend(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tnumtotal += **the_iterator;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tfailpass(\"Reverse iteration count test\", total == 400);\r\n\t\t\tfailpass(\"Reverse iterator access test\", numtotal == 6000);\r\n\r\n\t\t\tcolony<int *>::reverse_iterator r_iterator = p_colony.rbegin();\r\n\t\t\tadvance(r_iterator, 50);\r\n\r\n\t\t\tfailpass(\"Reverse iterator advance and distance test\", distance(p_colony.rbegin(), r_iterator) == 50);\r\n\r\n\t\t\tcolony<int *>::reverse_iterator r_iterator2 = next(r_iterator, 2);\r\n\r\n\t\t\tfailpass(\"Reverse iterator next and distance test\", distance(p_colony.rbegin(), r_iterator2) == 52);\r\n\r\n\t\t\tnumtotal = 0;\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::iterator the_iterator = p_colony.begin(); the_iterator < p_colony.end(); advance(the_iterator, 2))\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tnumtotal += **the_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Multiple iteration test\", total == 200);\r\n\t\t\tfailpass(\"Multiple iteration access test\", numtotal == 2000);\r\n\r\n\t\t\tnumtotal = 0;\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::const_iterator the_iterator = p_colony.cbegin(); the_iterator != p_colony.cend(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tnumtotal += **the_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Const_iterator test\", total == 400);\r\n\t\t\tfailpass(\"Const_iterator access test\", numtotal == 6000);\r\n\r\n\r\n\t\t\tnumtotal = 0;\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::const_reverse_iterator the_iterator = --colony<int *>::const_reverse_iterator(p_colony.crend()); the_iterator != colony<int *>::const_reverse_iterator(p_colony.crbegin()); --the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tnumtotal += **the_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Const_reverse_iterator -- test\", total == 399);\r\n\t\t\tfailpass(\"Const_reverse_iterator -- access test\", numtotal == 5980);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::iterator the_iterator = ++colony<int *>::iterator(p_colony.begin()); the_iterator < p_colony.end(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t\tthe_iterator = p_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Partial erase iteration test\", total == 200);\r\n\t\t\tfailpass(\"Post-erase size test\", p_colony.size() == 200);\r\n\r\n\t\t\tconst unsigned int temp_capacity = static_cast<unsigned int>(p_colony.capacity());\r\n\t\t\tp_colony.shrink_to_fit();\r\n\t\t\tfailpass(\"Shrink_to_fit test\", p_colony.capacity() < temp_capacity);\r\n\t\t\tfailpass(\"Shrink_to_fit test 2\", p_colony.capacity() == 200);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::reverse_iterator the_iterator = p_colony.rbegin(); the_iterator != p_colony.rend(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\tcolony<int *>::iterator it = the_iterator.base();\r\n\t\t\t\tthe_iterator = p_colony.erase(--it);\r\n\t\t\t\t++total;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Full erase reverse iteration test\", total == 200);\r\n\t\t\tfailpass(\"Post-erase size test\", p_colony.size() == 0);\r\n\r\n\t\t\tfor (unsigned int temp = 0; temp != 200; ++temp)\r\n\t\t\t{\r\n\t\t\t\tp_colony.insert(&ten);\r\n\t\t\t\tp_colony.insert(&twenty);\r\n\t\t\t}\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::iterator the_iterator = --colony<int *>::iterator(p_colony.end()); the_iterator != p_colony.begin(); --the_iterator)\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Negative iteration test\", total == 399);\r\n\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor(colony<int *>::iterator the_iterator = --(colony<int *>::iterator(p_colony.end())); the_iterator != p_colony.begin(); advance(the_iterator, -2))\r\n\t\t\t{\r\n\t\t\t\t++total;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Negative multiple iteration test\", total == 200);\r\n\r\n\t\t\t#ifdef PLF_TEST_MOVE_SEMANTICS_SUPPORT\r\n\t\t\t\tp_colony2 = std::move(p_colony);\r\n\t\t\t\tfailpass(\"Move test\", p_colony2.size() == 400);\r\n\r\n\t\t\t\tp_colony.insert(&ten);\r\n\r\n\t\t\t\tfailpass(\"Insert to post-moved-colony test\", p_colony.size() == 1);\r\n\r\n\t\t\t\tcolony<int *> p_colony5(p_colony2);\r\n\t\t\t\tcolony<int *> p_colony6(std::move(p_colony5), p_colony2.get_allocator());\r\n\r\n\t\t\t\tfailpass(\"Allocator-extended move construct test\", p_colony6.size() == 400);\r\n\t\t\t#else\r\n\t\t\t\tp_colony2 = p_colony;\r\n\t\t\t#endif\r\n\r\n\t\t\tp_colony3 = p_colony2;\r\n\r\n\t\t\tfailpass(\"Copy test 2\", p_colony3.size() == 400);\r\n\r\n\t\t\tp_colony2.insert(&ten);\r\n\r\n\t\t\tp_colony2.swap(p_colony3);\r\n\r\n\t\t\tfailpass(\"Swap test\", p_colony2.size() == p_colony3.size() - 1);\r\n\r\n\t\t\tstd::swap(p_colony2, p_colony3);\r\n\r\n\t\t\tfailpass(\"Swap test 2\", p_colony3.size() == p_colony2.size() - 1);\r\n\r\n\t\t\tfailpass(\"max_size() test\", p_colony2.max_size() > p_colony2.size());\r\n\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Iterator comparison tests\");\r\n\r\n\t\t\tcolony<int> i_colony;\r\n\r\n\t\t\tfor (int temp = 0; temp != 10; ++temp)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(temp);\r\n\t\t\t}\r\n\r\n\t\t\tcolony<int>::iterator it1 = i_colony.begin(), it2 = i_colony.begin();\r\n\r\n\t\t\t++it2;\r\n\t\t\t++it2;\r\n\t\t\t++it2;\r\n\r\n\t\t\tfailpass(\"Iterator ++ test\", *it2 == 3);\r\n\r\n\t\t\tfailpass(\"Iterator > test\", it2 > it1);\r\n\r\n\t\t\tfailpass(\"Iterator >= test\", it2 >= it1);\r\n\r\n\t\t\tfailpass(\"Iterator < test\", it1 < it2);\r\n\r\n\t\t\tfailpass(\"Iterator <= test\", it1 <= it2);\r\n\r\n\t\t\tfailpass(\"Iterator != test\", it2 != it1);\r\n\r\n\t\t\t#ifdef PLF_TEST_CPP20_SUPPORT\r\n\t\t\t\tfailpass(\"Iterator <=> test 1\", (it2 <=> it1) == 1);\r\n\r\n\t\t\t\tfailpass(\"Iterator <=> test 2\", (it1 <=> it2) == -1);\r\n\r\n\t\t\t\tit1 = it2;\r\n\r\n\t\t\t\tfailpass(\"Iterator <=> test 3\", (it1 <=> it2) == 0);\r\n\t\t\t#endif\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Insert and Erase tests\");\r\n\r\n\t\t\tcolony<int> i_colony;\r\n\r\n\t\t\tfor (int temp = 0; temp != 500000; ++temp)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(temp);\r\n\t\t\t}\r\n\r\n\r\n\t\t\tfailpass(\"Size after insert test\", i_colony.size() == 500000);\r\n\r\n\r\n\t\t\tcolony<int>::iterator found_item = std::find(i_colony.begin(), i_colony.end(), 5000);;\r\n\r\n\t\t\tfailpass(\"std::find iterator test\", *found_item == 5000);\r\n\r\n\r\n\t\t\tcolony<int>::reverse_iterator found_item2 = std::find(i_colony.rbegin(), i_colony.rend(), 5000);;\r\n\r\n\t\t\tfailpass(\"std::find reverse_iterator test\", *found_item2 == 5000);\r\n\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Erase alternating test\", i_colony.size() == 250000);\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++the_iterator;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} while (!i_colony.empty());\r\n\r\n\t\t\tfailpass(\"Erase randomly till-empty test\", i_colony.size() == 0);\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\t\t\ti_colony.reshape(plf::colony_limits(10000, i_colony.block_limits().max));\r\n\r\n\t\t\ti_colony.insert(30000, 1); // fill-insert 30000 elements\r\n\r\n\t\t\tfailpass(\"Size after reinitialize + fill-insert test\", i_colony.size() == 30000);\r\n\r\n\t\t\tunsigned short count2 = 0;\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t\t\t\t++count2;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++the_iterator;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t} while (count2 < 15000);\r\n\r\n\t\t\tfailpass(\"Erase randomly till half-empty test\", i_colony.size() == 30000u - count2);\r\n\r\n\t\t\ti_colony.insert(count2, 1);\r\n\r\n\t\t\tfailpass(\"Size after reinsert test\", i_colony.size() == 30000);\r\n\r\n\r\n\r\n\r\n\t\t\tunsigned int sum = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t{\r\n\t\t\t\tif (++sum == 3)\r\n\t\t\t\t{\r\n\t\t\t\t\tsum = 0;\r\n\t\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t\t}\r\n\t\t\t\telse\r\n\t\t\t\t{\r\n\t\t\t\t\ti_colony.insert(1);\r\n\t\t\t\t\t++the_iterator;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Alternating insert/erase test\", i_colony.size() == 45001);\r\n\r\n\r\n\t\t\tdo\r\n\t\t\t{\r\n\t\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 3) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++the_iterator;\r\n\t\t\t\t\t\ti_colony.insert(1);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t} while (!i_colony.empty());;\r\n\r\n\t\t\tfailpass(\"Random insert/erase till empty test\", i_colony.size() == 0);\r\n\r\n\r\n\t\t\ti_colony.insert(500000, 10);\r\n\r\n\t\t\tfailpass(\"Insert post-erase test\", i_colony.size() == 500000);\r\n\t\t\tcolony<int>::iterator it2 = i_colony.begin();\r\n\t\t\tadvance(it2, 250000);\r\n\r\n\r\n\t\t\tfor (; it2 != i_colony.end();)\r\n\t\t\t{\r\n\t\t\t\tit2 = i_colony.erase(it2);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Large multi-increment iterator test\", i_colony.size() == 250000);\r\n\r\n\t\t\ti_colony.insert(250000, 10);\r\n\r\n\t\t\tcolony<int>::iterator end_iterator = i_colony.end();\r\n\t\t\tcolony<int>::iterator end_iterator2 = i_colony.end();\r\n\t\t\tadvance(end_iterator, -250000);\r\n\r\n\t\t\tfor (unsigned int count = 0; count != 250000; ++count, --end_iterator2){}\r\n\t\t\tfailpass(\"Large multi-decrement iterator test 1\", end_iterator == end_iterator2);\r\n\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != end_iterator;)\r\n\t\t\t{\r\n\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Large multi-decrement iterator test\", i_colony.size() == 250000);\r\n\r\n\r\n\r\n\t\t\ti_colony.insert(250000, 10);\r\n\t\t\tint total = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end(); ++the_iterator)\r\n\t\t\t{\r\n\t\t\t\ttotal += *the_iterator;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Re-insert post-heavy-erasure test\", total == 5000000);\r\n\r\n\r\n\t\t\tend_iterator = i_colony.end();\r\n\t\t\tadvance(end_iterator, -50001);\r\n\t\t\tcolony<int>::iterator begin_iterator = i_colony.begin();\r\n\t\t\tadvance(begin_iterator, 300000);\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = begin_iterator; the_iterator != end_iterator;)\r\n\t\t\t{\r\n\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Non-end decrement + erase test\", i_colony.size() == 350001);\r\n\r\n\r\n\t\t\ti_colony.insert(100000, 10);\r\n\r\n\t\t\tbegin_iterator = i_colony.begin();\r\n\t\t\tadvance(begin_iterator, 300001);\r\n\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = begin_iterator; the_iterator != i_colony.end();)\r\n\t\t\t{\r\n\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Non-beginning increment + erase test\", i_colony.size() == 300001);\r\n\r\n\t\t\tcolony<int>::iterator temp_iterator = i_colony.begin();\r\n\t\t\tadvance(temp_iterator, 20); // Advance test 1\r\n\r\n\t\t\tunsigned int index = static_cast<unsigned int>(distance(i_colony.begin(), temp_iterator));\r\n\t\t\tfailpass(\"Advance + iterator-to-index test\", index == 20);\r\n\r\n\t\t\ti_colony.erase(temp_iterator);\r\n\t\t\ttemp_iterator = i_colony.begin(); // Check edge-case with advance when erasures present in initial group\r\n\t\t\tadvance(temp_iterator, 500);\r\n\r\n\t\t\tindex = static_cast<unsigned int>(distance(i_colony.begin(), temp_iterator));\r\n\r\n\t\t\tfailpass(\"Advance + iterator-to-index test\", index == 500);\r\n\r\n\t\t\tcolony<int>::iterator temp2 = i_colony.get_iterator(&(*temp_iterator));\r\n\r\n\t\t\tfailpass(\"Pointer-to-iterator test\", temp2 != i_colony.end());\r\n\r\n\t\t\ttemp2 = i_colony.begin();\r\n\t\t\tadvance(temp2, 500);\r\n\r\n\t\t\tfailpass(\"Index-to-iterator test\", temp2 == temp_iterator);\r\n\r\n\r\n\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t{\r\n\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Total erase test\", i_colony.empty());\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\t\t\ti_colony.reshape(plf::colony_limits(3, i_colony.block_limits().max));\r\n\r\n\t\t\tconst unsigned int temp_capacity2 = static_cast<unsigned int>(i_colony.capacity());\r\n\t\t\ti_colony.reserve(100000);\r\n\t\t\tfailpass(\"Colony reserve test\", temp_capacity2 != i_colony.capacity());\r\n\r\n\t\t\ti_colony.insert(110000, 1);\r\n\r\n\t\t\tfailpass(\"Post-reserve insert test\", i_colony.size() == 110000);\r\n\r\n\t\t\tunsigned int count = 110000;\r\n\r\n\t\t\tfor (unsigned int loop1 = 0; loop1 != 50000; ++loop1)\r\n\t\t\t{\r\n\t\t\t\tfor (unsigned int loop = 0; loop != 10; ++loop)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\ti_colony.insert(1);\r\n\t\t\t\t\t\t++count;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tunsigned int internal_loop_counter = 0;\r\n\r\n\t\t\t\tfor (colony<int>::iterator the_iterator = i_colony.begin(); the_iterator != i_colony.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tthe_iterator = i_colony.erase(the_iterator);\r\n\t\t\t\t\t\t--count;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++the_iterator;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t++internal_loop_counter;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Multiple sequential small insert/erase commands test\", count == i_colony.size());\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Range-erase tests\");\r\n\r\n\t\t\tcolony<int> i_colony;\r\n\r\n\t\t\tint counter = 0;\r\n\r\n\t\t\tfor (; counter != 1000; ++counter)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(counter);\r\n\t\t\t}\r\n\r\n\r\n\t\t\tcolony<int>::iterator it1 = i_colony.begin(), it2 = i_colony.begin();\r\n\r\n\t\t\tadvance(it1, 500);\r\n\t\t\tadvance(it2, 800);\r\n\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Simple range-erase test 1\", counter == 700 && i_colony.size() == 700);\r\n\r\n\r\n\t\t\tit1 = it2 = i_colony.begin();\r\n\r\n\t\t\tadvance(it1, 400);\r\n\t\t\tadvance(it2, 500); // This should put it2 past the point of previous erasures\r\n\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Simple range-erase test 2\", counter == 600 && i_colony.size() == 600);\r\n\r\n\r\n\r\n\t\t\tit2 = it1 = i_colony.begin();\r\n\r\n\t\t\tadvance(it1, 4);\r\n\t\t\tadvance(it2, 9); // This should put it2 past the point of previous erasures\r\n\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Simple range-erase test 3\", counter == 595 && i_colony.size() == 595);\r\n\r\n\r\n\r\n\r\n\t\t\tit2 = it1 = i_colony.begin();\r\n\r\n\t\t\tadvance(it2, 50);\r\n\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Range-erase from begin() test 1\", counter == 545 && i_colony.size() == 545);\r\n\r\n\r\n\r\n\r\n\t\t\tit1 = i_colony.begin();\r\n\t\t\tit2 = i_colony.end();\r\n\r\n\t\t\tadvance(it1, 345); // Test erasing and validity when it removes the final group in colony\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Range-erase to end() test 1\", counter == 345 && i_colony.size() == 345);\r\n\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\tfor (counter = 0; counter != 3000; ++counter)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(counter);\r\n\t\t\t}\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it < i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\tit = i_colony.erase(it);\r\n\t\t\t}\r\n\r\n\t\t\tit2 = it1 = i_colony.begin();\r\n\r\n\t\t\tadvance(it1, 4);\r\n\t\t\tadvance(it2, 600);\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Range-erase with colony already half-erased, alternating erasures\", counter == 904 && i_colony.size() == 904);\r\n\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\tfor (counter = 0; counter != 3000; ++counter)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(counter);\r\n\t\t\t}\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it < i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\tif ((plf::rand() & 1) == 0)\r\n\t\t\t\t{\r\n\t\t\t\t\tit = i_colony.erase(it);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (i_colony.size() < 400)\r\n\t\t\t{\r\n\t\t\t\tfor (counter = 0; counter != 400; ++counter)\r\n\t\t\t\t{\r\n\t\t\t\t\ti_colony.insert(counter);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tit1 = i_colony.begin();\r\n\t\t\tit2 = i_colony.end();\r\n\r\n\t\t\tadvance(it1, 400);\r\n\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\tcounter = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\t++counter;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Range-erase with colony already third-erased, randomized erasures\", counter == 400 && i_colony.size() == 400);\r\n\r\n\r\n\r\n\t\t\tunsigned int size, range1, range2, internal_loop_counter;\r\n\r\n\t\t\tfor (unsigned int loop_counter = 0; loop_counter != 50; ++loop_counter)\r\n\t\t\t{\r\n\t\t\t\ti_colony.clear();\r\n\r\n\t\t\t\tfor (counter = 0; counter != 1000; ++counter)\r\n\t\t\t\t{\r\n\t\t\t\t\ti_colony.insert(counter);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinternal_loop_counter = 0;\r\n\r\n\t\t\t\twhile (!i_colony.empty())\r\n\t\t\t\t{\r\n\t\t\t\t\tit2 = it1 = i_colony.begin();\r\n\r\n\t\t\t\t\tsize = static_cast<unsigned int>(i_colony.size());\r\n\t\t\t\t\trange1 = plf::rand() % size;\r\n\t\t\t\t\trange2 = range1 + 1 + (plf::rand() % (size - range1));\r\n\t\t\t\t\tadvance(it1, static_cast<int>(range1));\r\n\t\t\t\t\tadvance(it2, static_cast<int>(range2));\r\n\r\n\t\t\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\t\t\tcounter = 0;\r\n\r\n\t\t\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++counter;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(counter))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase randomly Fail: loop counter: %u, internal_loop_counter: %u.\\n\", loop_counter, internal_loop_counter);\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() != i_colony.group_size_sum())\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase randomly Fail - group_size_sum failure: loop counter: %u, internal_loop_counter: %u, size: %u, group_size_sum: %u.\\n\", loop_counter, internal_loop_counter, static_cast<unsigned int>(i_colony.size()), static_cast<unsigned int>(i_colony.group_size_sum()));\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() > 2)\r\n\t\t\t\t\t{ // Test to make sure our stored erased_locations are valid\r\n\t\t\t\t\t\ti_colony.insert(1);\r\n\t\t\t\t\t\ti_colony.insert(10);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t++internal_loop_counter;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Fuzz-test range-erase randomly until empty\", i_colony.size() == 0);\r\n\r\n\r\n\r\n\t\t\tfor (unsigned int loop_counter = 0; loop_counter != 50; ++loop_counter)\r\n\t\t\t{\r\n\t\t\t\ti_colony.clear();\r\n\t\t\t\tinternal_loop_counter = 0;\r\n\r\n\t\t\t\ti_colony.insert(10000, 10);\r\n\r\n\t\t\t\twhile (!i_colony.empty())\r\n\t\t\t\t{\r\n\t\t\t\t\tit2 = it1 = i_colony.begin();\r\n\r\n\t\t\t\t\tsize = static_cast<unsigned int>(i_colony.size());\r\n\t\t\t\t\trange1 = plf::rand() % size;\r\n\t\t\t\t\trange2 = range1 + 1 + (plf::rand() % (size - range1));\r\n\t\t\t\t\tadvance(it1, static_cast<int>(range1));\r\n\t\t\t\t\tadvance(it2, static_cast<int>(range2));\r\n\r\n\t\t\t\t\ti_colony.erase(it1, it2);\r\n\r\n\t\t\t\t\tcounter = 0;\r\n\r\n\t\t\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++counter;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() != i_colony.group_size_sum())\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase + fill-insert randomly Fails during erase - group_size_sum failure: loop counter: %u, internal_loop_counter: %u, size: %u, group_size_sum: %u.\\n\", loop_counter, internal_loop_counter, static_cast<unsigned int>(i_colony.size()), static_cast<unsigned int>(i_colony.group_size_sum()));\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(counter))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase + fill-insert randomly Fails during erase: loop counter: %u, internal_loop_counter: %u.\\n\", loop_counter, internal_loop_counter);\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (i_colony.size() > 100)\r\n\t\t\t\t\t{ // Test to make sure our stored erased_locations are valid & fill-insert is functioning properly in these scenarios\r\n\t\t\t\t\t\tconst unsigned int extra_size = plf::rand() & 127;\r\n\t\t\t\t\t\ti_colony.insert(extra_size, 5);\r\n\r\n\t\t\t\t\t\tif (i_colony.size() != i_colony.group_size_sum())\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tprintf(\"Fuzz-test range-erase + fill-insert randomly Fails during insert - group_size_sum failure: loop counter: %u, internal_loop_counter: %u, size: %u, group_size_sum: %u.\\n\", loop_counter, internal_loop_counter, static_cast<unsigned int>(i_colony.size()), static_cast<unsigned int>(i_colony.group_size_sum()));\r\n\t\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\t\tabort();\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(counter) + extra_size)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tprintf(\"Fuzz-test range-erase + fill-insert randomly Fails during fill-insert: loop counter: %u, internal_loop_counter: %u.\\n\", loop_counter, internal_loop_counter);\r\n\t\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\t\tabort();\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tcounter = 0;\r\n\r\n\t\t\t\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t++counter;\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(counter))\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tprintf(\"Fuzz-test range-erase + fill-insert randomly Fails during counter-test fill-insert: loop counter: %u, internal_loop_counter: %u.\\n\", loop_counter, internal_loop_counter);\r\n\t\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\t\tabort();\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t++internal_loop_counter;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Fuzz-test range-erase + fill-insert randomly until empty\", i_colony.size() == 0);\r\n\r\n\t\t\ti_colony.erase(i_colony.begin(), i_colony.end());\r\n\r\n\t\t\tfailpass(\"Range-erase when colony is empty test (crash test)\", i_colony.size() == 0);\r\n\r\n\t\t\ti_colony.insert(10, 1);\r\n\r\n\t\t\ti_colony.erase(i_colony.begin(), i_colony.begin());\r\n\r\n\t\t\tfailpass(\"Range-erase when range is empty test (crash test)\", i_colony.size() == 10);\r\n\t\t}\r\n\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle1(\"Non-trivial type tests\");\r\n\r\n\t\t\tcolony<small_struct_non_trivial> ss_nt;\r\n\t\t\tcolony<small_struct_non_trivial>::iterator ss_it1, ss_it2;\r\n\r\n\t\t\tsmall_struct_non_trivial ss(5);\r\n\r\n\t\t\tunsigned int size, range1 = 0, range2 = 0, internal_loop_counter;\r\n\t\t\tint counter, sum1 = 0;\r\n\r\n\t\t\tss_nt.insert(10000, ss);\r\n\r\n\t\t\tfailpass(\"Non-trivial type insert test\", ss_nt.size() == 10000);\r\n\r\n\r\n\t\t\tfor (colony<small_struct_non_trivial>::iterator ss_it = ss_nt.begin(); ss_it != ss_nt.end(); ++ss_it)\r\n\t\t\t{\r\n\t\t\t\tss_it = ss_nt.erase(ss_it);\r\n\t\t\t\tsum1 += ss_it->number;\r\n\t\t\t\t++range1;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Non-trivial type erase half of all elements\", ss_nt.size() == 5000);\r\n\r\n\r\n\t\t\tfor (unsigned int loop_counter = 0; loop_counter != 50; ++loop_counter)\r\n\t\t\t{\r\n\t\t\t\tss_nt.clear();\r\n\r\n\t\t\t\tfor (counter = 0; counter != 1000; ++counter)\r\n\t\t\t\t{\r\n\t\t\t\t\tss_nt.insert(counter);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinternal_loop_counter = 0;\r\n\r\n\t\t\t\twhile (!ss_nt.empty())\r\n\t\t\t\t{\r\n\t\t\t\t\tss_it2 = ss_it1 = ss_nt.begin();\r\n\r\n\t\t\t\t\tsize = static_cast<unsigned int>(ss_nt.size());\r\n\t\t\t\t\trange1 = plf::rand() % size;\r\n\t\t\t\t\trange2 = range1 + 1 + (plf::rand() % (size - range1));\r\n\t\t\t\t\tadvance(ss_it1, static_cast<int>(range1));\r\n\t\t\t\t\tadvance(ss_it2, static_cast<int>(range2));\r\n\r\n\t\t\t\t\tss_nt.erase(ss_it1, ss_it2);\r\n\r\n\t\t\t\t\tcounter = 0;\r\n\r\n\t\t\t\t\tfor (colony<small_struct_non_trivial>::iterator ss_it = ss_nt.begin(); ss_it != ss_nt.end(); ++ss_it)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++counter;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ss_nt.size() != static_cast<unsigned int>(counter))\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase randomly Fail: loop counter: %u, internal_loop_counter: %u.\\n\", loop_counter, internal_loop_counter);\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ss_nt.size() != ss_nt.group_size_sum())\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tprintf(\"Fuzz-test range-erase randomly Fail - group_size_sum failure: loop counter: %u, internal_loop_counter: %u, size: %u, group_size_sum: %u.\\n\", loop_counter, internal_loop_counter, static_cast<unsigned int>(ss_nt.size()), static_cast<unsigned int>(ss_nt.group_size_sum()));\r\n\t\t\t\t\t\tgetchar();\r\n\t\t\t\t\t\tabort();\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (ss_nt.size() > 2)\r\n\t\t\t\t\t{ // Test to make sure our stored erased_locations are valid\r\n\t\t\t\t\t\tss_nt.insert(1);\r\n\t\t\t\t\t\tss_nt.insert(10);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t++internal_loop_counter;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Non-trivial type fuzz-test range-erase randomly until empty\", ss_nt.size() == 0);\r\n\t\t}\r\n\r\n\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Sort tests\");\r\n\r\n\t\t\tcolony<int> i_colony;\r\n\r\n\t\t\ti_colony.reserve(50000);\r\n\r\n\t\t\tfor (unsigned int temp = 0; temp != 50000; ++temp)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(plf::rand() & 65535);\r\n\t\t\t}\r\n\r\n\t\t\ti_colony.sort();\r\n\r\n\t\t\tbool sorted = true;\r\n\t\t\tint previous = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator current = i_colony.begin(); current != i_colony.end(); ++current)\r\n\t\t\t{\r\n\t\t\t\tif (previous > *current)\r\n\t\t\t\t{\r\n\t\t\t\t\tsorted = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevious = *current;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Less-than sort test\", sorted);\r\n\r\n\t\t\ti_colony.sort(std::greater<int>());\r\n\r\n\t\t\tprevious = 65536;\r\n\r\n\t\t\tfor (colony<int>::iterator current = i_colony.begin(); current != i_colony.end(); ++current)\r\n\t\t\t{\r\n\t\t\t\tif (previous < *current)\r\n\t\t\t\t{\r\n\t\t\t\t\tsorted = false;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tprevious = *current;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Greater-than sort test\", sorted);\r\n\t\t}\r\n\r\n\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Different insertion-style tests\");\r\n\r\n\t\t\t#ifdef PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t\t\t\tcolony<int> i_colony({1, 2, 3});\r\n\r\n\t\t\t\tfailpass(\"Initializer-list constructor test\", i_colony.size() == 3);\r\n\t\t\t#else\r\n\t\t\t\tcolony<int> i_colony(3, 1);\r\n\t\t\t#endif\r\n\r\n\t\t\tcolony<int> i_colony2(i_colony.begin(), i_colony.end());\r\n\r\n\t\t\tfailpass(\"Range constructor test\", i_colony2.size() == 3);\r\n\r\n\t\t\tcolony<int> i_colony3(5000, 2, plf::colony_limits(100, 1000));\r\n\r\n\t\t\tfailpass(\"Fill construction test\", i_colony3.size() == 5000);\r\n\r\n\t\t\ti_colony2.insert(500000, 5);\r\n\r\n\t\t\tfailpass(\"Fill insertion test\", i_colony2.size() == 500003);\r\n\r\n\t\t\tstd::vector<int> some_ints(500, 2);\r\n\r\n\t\t\ti_colony2.insert(some_ints.begin(), some_ints.end());\r\n\r\n\t\t\tfailpass(\"Range insertion test\", i_colony2.size() == 500503);\r\n\r\n\t\t\t#ifdef PLF_TEST_CPP20_SUPPORT\r\n\t \t\t\ti_colony2.insert(some_ints.begin(), some_ints.cend());\r\n\r\n\t \t\t\tfailpass(\"Range insertion with differing iterators test\", i_colony2.size() == 501003);\r\n\t\t\t#endif\r\n\r\n\t\t\ti_colony3.clear();\r\n\t\t\ti_colony2.clear();\r\n\t\t\ti_colony2.reserve(50000);\r\n\t\t\ti_colony2.insert(60000, 1);\r\n\r\n\t\t\tint total = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony2.begin(); it != i_colony2.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Reserve + fill insert test\", i_colony2.size() == 60000 && total == 60000);\r\n\r\n\r\n\t\t\ti_colony2.clear();\r\n\t\t\ti_colony2.reserve(5000);\r\n\t\t\ti_colony2.insert(60, 1);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony2.begin(); it != i_colony2.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Reserve + fill insert test 2\", i_colony2.size() == 60 && total == 60);\r\n\r\n\t\t\ti_colony2.insert(6000, 1);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony2.begin(); it != i_colony2.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Reserve + fill + fill test\", i_colony2.size() == 6060 && total == 6060);\r\n\r\n\t\t\ti_colony2.reserve(18000);\r\n\t\t\ti_colony2.insert(6000, 1);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony2.begin(); it != i_colony2.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Reserve + fill + fill + reserve + fill test\", i_colony2.size() == 12060 && total == 12060);\r\n\r\n\t\t\ti_colony2.clear();\r\n\t\t\ti_colony2.insert(6000, 2);\r\n\r\n\t\t\tfailpass(\"Clear + fill test\", i_colony2.size() == 6000 && *(i_colony2.begin()) == 2);\r\n\r\n\t\t\ti_colony.insert(i_colony2.begin(), i_colony2.end());\r\n\r\n\t\t\tfailpass(\"Range insert when not empty test\", i_colony.size() == 6003);\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Assign tests\");\r\n\r\n\t\t\tcolony<int> i_colony(50, 2);\r\n\r\n\t\t\ti_colony.assign(50, 1);\r\n\r\n\t\t\tint total = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Equal capacity assign test\", i_colony.size() == 50 && total == 50);\r\n\r\n\r\n\t\t\ti_colony.assign(10, 2);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Lesser capacity assign test\", i_colony.size() == 10 && total == 20);\r\n\r\n\r\n\t\t\ti_colony.assign(2000, 20);\r\n\r\n\t\t\ttotal = 0;\r\n\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal += *it;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Greater capacity assign test\", i_colony.size() == 2000 && total == 40000);\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\r\n\t\t\tfor (unsigned int internal_loop_counter = 0; internal_loop_counter != 10; ++internal_loop_counter)\r\n\t\t\t{\r\n\t\t\t\tconst unsigned int capacity = plf::rand() & 65535;\r\n\t\t\t\ti_colony.assign(capacity, 1);\r\n\r\n\t\t\t\ttotal = 0;\r\n\r\n\t\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t\t{\r\n\t\t\t\t\ttotal += *it;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (i_colony.size() != capacity)\r\n\t\t\t\t{\r\n\t\t\t\t\tprintf(\"Fuzz-test assign capacity Fail: global loop counter: %u, internal loop counter: %u.\\n\", looper, internal_loop_counter);\r\n\t\t\t\t\tgetchar();\r\n\t\t\t\t\tabort();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(total))\r\n\t\t\t\t{\r\n\t\t\t\t\tprintf(\"Fuzz-test assign sum Fail: global loop counter: %u, internal loop counter: %u.\\n\", looper, internal_loop_counter);\r\n\t\t\t\t\tgetchar();\r\n\t\t\t\t\tabort();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tmessage(\"Fuzz-test assign passed.\");\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\tstd::vector<int> i_vector;\r\n\r\n\t\t\tfor (int counter = 1; counter != 11; ++counter)\r\n\t\t\t{\r\n\t\t\t\ti_vector.push_back(counter);\r\n\t\t\t}\r\n\r\n\t\t\ti_colony.assign(i_vector.begin(), i_vector.end());\r\n\r\n\t\t\tcolony<int>::iterator it = i_colony.begin();\r\n\t\t\tbool fail = false;\r\n\r\n\t\t\tfor (int counter = 1; counter != 11; ++counter, ++it)\r\n\t\t\t{\r\n\t\t\t\tif (*it != counter)\r\n\t\t\t\t{\r\n\t\t\t\t\tfail = true;\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Range assign test\", i_colony.size() == 10 && !fail);\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\r\n\t\t\tfor (unsigned int internal_loop_counter = 0; internal_loop_counter != 10; ++internal_loop_counter)\r\n\t\t\t{\r\n\t\t\t\tconst unsigned int capacity = plf::rand() & 65535;\r\n\t\t\t\ti_vector.assign(capacity, 1);\r\n\t\t\t\ti_colony.assign(i_vector.begin(), i_vector.end());\r\n\r\n\t\t\t\ttotal = 0;\r\n\r\n\t\t\t\tfor (colony<int>::iterator it3 = i_colony.begin(); it3 != i_colony.end(); ++it3)\r\n\t\t\t\t{\r\n\t\t\t\t\ttotal += *it3;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (i_colony.size() != capacity)\r\n\t\t\t\t{\r\n\t\t\t\t\tprintf(\"Fuzz-test range assign capacity Fail: global loop counter: %u, internal loop counter: %u.\\n\", looper, internal_loop_counter);\r\n\t\t\t\t\tgetchar();\r\n\t\t\t\t\tabort();\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (i_colony.size() != static_cast<unsigned int>(total))\r\n\t\t\t\t{\r\n\t\t\t\t\tprintf(\"Fuzz-test range assign sum Fail: global loop counter: %u, internal loop counter: %u.\\n\", looper, internal_loop_counter);\r\n\t\t\t\t\tgetchar();\r\n\t\t\t\t\tabort();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tmessage(\"Fuzz-test range assign passed.\");\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\t#ifdef PLF_TEST_INITIALIZER_LIST_SUPPORT\r\n\t\t\t\ti_colony.assign({1, 2, 3, 4, 5, 6, 7, 8, 9, 10});\r\n\t\t\t\tit = i_colony.begin();\r\n\r\n\t\t\t\tfor (int counter = 1; counter != 11; ++counter, ++it)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (*it != counter)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Initializer_list assign test\", i_colony.size() == 10 && !fail);\r\n\r\n\t\t\t\ti_colony.clear();\r\n\t\t\t#endif\r\n\t\t}\r\n\r\n\r\n\t\t#ifdef PLF_TEST_VARIADICS_SUPPORT\r\n\t\t{\r\n\t\t\ttitle2(\"Perfect Forwarding tests\");\r\n\r\n\t\t\tcolony<perfect_forwarding_test> pf_colony;\r\n\r\n\t\t\tint lvalue = 0;\r\n\t\t\tint &lvalueref = lvalue;\r\n\r\n\t\t\tpf_colony.emplace(7, lvalueref);\r\n\r\n\t\t\tfailpass(\"Perfect forwarding test\", (*pf_colony.begin()).success);\r\n\t\t\tfailpass(\"Perfect forwarding test 2\", lvalueref == 1);\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Basic emplace test\");\r\n\r\n\t\t\tcolony<small_struct> ss_colony;\r\n\t\t\tint total1 = 0, total2 = 0;\r\n\r\n\t\t\tfor (int counter = 0; counter != 100; ++counter)\r\n\t\t\t{\r\n\t\t\t\tss_colony.emplace(counter);\r\n\t\t\t\ttotal1 += counter;\r\n\t\t\t}\r\n\r\n\t\t\tfor (colony<small_struct>::iterator it = ss_colony.begin(); it != ss_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\ttotal2 += it->number;\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Basic emplace test\", total1 == total2);\r\n\t\t\tfailpass(\"Basic emplace test 2\", ss_colony.size() == 100);\r\n\t\t}\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Non-copyable type test\");\r\n\r\n\t\t\tcolony<non_copyable_type> temp;\r\n\r\n\t\t\ttemp.emplace(1);\r\n\t\t\ttemp.emplace(2);\r\n\r\n\t\t\tfailpass(\"Non-copyable size test\", temp.size() == 2);\r\n\t\t}\r\n\r\n\r\n\t\t#endif\r\n\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Misc function tests\");\r\n\r\n\t\t\tcolony<int> colony1;\r\n\t\t\tcolony1.reshape(plf::colony_limits(50, 100));\r\n\r\n\t\t\tcolony1.insert(27);\r\n\r\n\t\t\tfailpass(\"Change_group_sizes min-size test\", colony1.capacity() == 50);\r\n\r\n\t\t\tfor (int counter = 0; counter != 100; ++counter)\r\n\t\t\t{\r\n\t\t\t\tcolony1.insert(counter);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Change_group_sizes max-size test\", colony1.capacity() == 200);\r\n\r\n\t\t\tcolony1.clear();\r\n\t\t\tcolony1.reshape(plf::colony_limits(200, 2000));\r\n\r\n\t\t\tcolony1.insert(27);\r\n\r\n\t\t\tfailpass(\"Reinitialize min-size test\", colony1.capacity() == 200);\r\n\r\n\t\t\tplf::colony_limits temp_limits = colony1.block_limits();\r\n\r\n\t\t\tfailpass(\"get_block_limits test\", temp_limits.min == 200 && temp_limits.max == 2000);\r\n\r\n\t\t\tfor (int counter = 0; counter != 3300; ++counter)\r\n\t\t\t{\r\n\t\t\t\tcolony1.insert(counter);\r\n\t\t\t}\r\n\r\n\t\t\tfailpass(\"Reinitialize max-size test\", colony1.capacity() == 5200);\r\n\r\n\t\t\tcolony1.reshape(plf::colony_limits(500, 500));\r\n\r\n\t\t\tfailpass(\"Change_group_sizes resize test\", colony1.capacity() == 3500);\r\n\r\n\t\t\tcolony1.reshape(plf::colony_limits(200, 200));\r\n\r\n\t\t\tfailpass(\"Change_maximum_group_size resize test\", colony1.capacity() == 3400);\r\n\r\n\t\t}\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"Splice tests\");\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 20; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number);\r\n\t\t\t\t\tcolony2.insert(number + 20);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = 0;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number++ != *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Small splice test 1\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 100; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number);\r\n\t\t\t\t\tcolony2.insert(number + 100);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = 0;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number++ != *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Small splice test 2\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 100000; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number);\r\n\t\t\t\t\tcolony2.insert(number + 100000);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = 0;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number++ != *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Large splice test 1\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 100; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number);\r\n\t\t\t\t\tcolony2.insert(number + 100);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony2.begin(); current != colony2.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcurrent = colony2.erase(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++current;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = -1;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number >= *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcheck_number = *current;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Erase + splice test 1\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 100; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number);\r\n\t\t\t\t\tcolony2.insert(number + 100);\r\n\t\t\t\t}\r\n\r\n\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony2.begin(); current != colony2.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 3) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcurrent = colony2.erase(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++current;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 1) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcurrent = colony1.erase(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++current;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = -1;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number >= *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcheck_number = *current;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Erase + splice test 2\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tcolony1.reshape(plf::colony_limits(200, 200));\r\n\t\t\t\tcolony2.reshape(plf::colony_limits(200, 200));\r\n\r\n\t\t\t\tfor(int number = 0; number != 100; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number + 150);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor(int number = 0; number != 150; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony2.insert(number);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = -1;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number >= *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcheck_number = *current;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Unequal size splice test 1\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1(plf::colony_limits(200, 200)), colony2(plf::colony_limits(200, 200));\r\n\r\n\t\t\t\tfor(int number = 0; number != 100; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(100 - number);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor(int number = 0; number != 150; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony2.insert(250 - number);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tcolony1.splice(colony2);\r\n\r\n\t\t\t\tint check_number = 255;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number < *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcheck_number = *current;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Unequal size splice test 2\", fail == false);\r\n\t\t\t}\r\n\r\n\r\n\r\n\t\t\t{\r\n\t\t\t\tcolony<int> colony1, colony2;\r\n\r\n\t\t\t\tfor(int number = 0; number != 100000; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony1.insert(number + 200000);\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor(int number = 0; number != 200000; ++number)\r\n\t\t\t\t{\r\n\t\t\t\t\tcolony2.insert(number);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony2.begin(); current != colony2.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 1) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcurrent = colony2.erase(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++current;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end();)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((plf::rand() & 1) == 0)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tcurrent = colony1.erase(current);\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t++current;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\r\n\t\t\t\tcolony1.erase(--(colony1.end()));\r\n\t\t\t\tcolony2.erase(--(colony2.end()));\r\n\r\n\t\t\t\tcolony1.splice(colony2); // splice should swap the order at this point due to differences in numbers of unused elements at end of final group in each colony\r\n\r\n\t\t\t\tint check_number = -1;\r\n\t\t\t\tbool fail = false;\r\n\r\n\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end(); ++current)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (check_number >= *current)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tfail = true;\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tcheck_number = *current;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfailpass(\"Large unequal size + erase splice test 1\", fail == false);\r\n\r\n\r\n\t\t\t\tdo\r\n\t\t\t\t{\r\n\t\t\t\t\tfor (colony<int>::iterator current = colony1.begin(); current != colony1.end();)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tif ((plf::rand() & 3) == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tcurrent = colony1.erase(current);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse if ((plf::rand() & 7) == 0)\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tcolony1.insert(433);\r\n\t\t\t\t\t\t\t++current;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t++current;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t} while (!colony1.empty());\r\n\r\n\t\t\t\tfailpass(\"Post-splice insert-and-erase randomly till-empty test\", colony1.size() == 0);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"erase_if tests\");\r\n\r\n\t\t\tcolony<int> i_colony(100, 100);\r\n\r\n\t\t\ti_colony.insert(100, 200);\r\n\t\t\tcolony<int> i_colony2 = i_colony;\r\n\r\n\t\t\terase(i_colony, 100);\r\n\t\t\tint total = std::accumulate(i_colony.begin(), i_colony.end(), 0);\r\n\r\n\t\t\tfailpass(\"non-member erase test 1\", total == 20000);\r\n\r\n\t\t\terase(i_colony2, 200);\r\n\t\t\ttotal = std::accumulate(i_colony2.begin(), i_colony2.end(), 0);\r\n\r\n\t\t\tfailpass(\"non-member erase test 2\", total == 10000);\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\tfor(int count = 0; count != 1000; ++count)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert((plf::rand() & 1));\r\n\t\t\t}\r\n\r\n\t\t\ti_colony2 = i_colony;\r\n\r\n\t\t\tconst int count0 = static_cast<int>(std::count(i_colony.begin(), i_colony.end(), 0));\r\n\t\t\tconst int count1 = 1000 - count0;\r\n\r\n\t\t\terase(i_colony, 0);\r\n\t\t\tfailpass(\"random non-member erase test 1\", static_cast<int>(i_colony.size()) == count1);\r\n\r\n\t\t\terase(i_colony2, 1);\r\n\t\t\tfailpass(\"random non-member erase test 2\",  static_cast<int>(i_colony2.size()) == count0);\r\n\r\n\r\n\t\t\ti_colony.clear();\r\n\r\n\t\t\tfor(int count = 0; count != 1000; ++count)\r\n\t\t\t{\r\n\t\t\t\ti_colony.insert(count);\r\n\t\t\t}\r\n\r\n\t\t\t#ifdef PLF_TEST_MOVE_SEMANTICS_SUPPORT // approximating checking for C++11 here\r\n\t\t\t\terase_if(i_colony, std::bind(std::greater<int>(), std::placeholders::_1, 499));\r\n\t\t\t#else // C++03 or lower\r\n\t\t\t\terase_if(i_colony, std::bind2nd(std::greater<int>(), 499));\r\n\t\t\t#endif\r\n\r\n\t\t\tfailpass(\"erase_if test\",\tstatic_cast<int>(i_colony.size()) == 500);\r\n\r\n\t\t}\r\n\r\n\t\t{\r\n\t\t\ttitle2(\"data() tests\");\r\n\r\n\t\t\tcolony<int> i_colony(10000, 5);\r\n\r\n\t\t\tint sum1 = 0, sum2 = 0, range1 = 0, range2 = 0;\r\n\r\n\r\n\t\t\t// Erase half of all elements and sum the rest:\r\n\t\t\tfor (colony<int>::iterator it = i_colony.begin(); it != i_colony.end(); ++it)\r\n\t\t\t{\r\n\t\t\t\tit = i_colony.erase(it);\r\n\t\t\t\tsum1 += *it;\r\n\t\t\t\t++range1;\r\n\t\t\t}\r\n\r\n\r\n\t\t\tcolony<int>::colony_data *data = i_colony.data();\r\n\r\n\t\t\t// Manually sum using raw memory blocks:\r\n\t\t\tfor (unsigned int block_num = 0; block_num != data->number_of_blocks; ++block_num)\r\n\t\t\t{\r\n\t\t\t\tcolony<int>::aligned_element_type *current_element = data->block_pointers[block_num];\r\n\t\t\t\tconst unsigned char *bitfield_location = data->bitfield_pointers[block_num];\r\n\t\t\t\tconst size_t capacity = data->block_capacities[block_num];\r\n\r\n\t\t\t\tsize_t char_index = 0;\r\n\t\t\t\tunsigned char offset = 0;\r\n\r\n\t\t\t\tfor (size_t index = 0; index != capacity; ++index, ++current_element)\r\n\t\t\t\t{\r\n\t\t\t\t\tif ((bitfield_location[char_index] >> offset) & 1)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tsum2 += *(reinterpret_cast<int *>(current_element));\r\n\t\t\t\t\t\t++range2;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (++offset == 8)\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\toffset = 0;\r\n\t\t\t\t\t\t++char_index;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tdelete data;\r\n\r\n\t\t\tfailpass(\"Manual summing pass over elements obtained from data()\", (sum1 == sum2) && (range1 == range2));\r\n\t\t}\r\n\t}\r\n}\r\n}\r\n\r\n#ifdef TEST_MAIN\r\nint main()\r\n{\r\n    sg14_test::plf_colony_test();\r\n}\r\n#endif\r\n"
  },
  {
    "path": "SG14_test/ring_test.cpp",
    "content": "#include \"SG14_test.h\"\n\n#include \"ring.h\"\n\n#include <array>\n#include <numeric>\n#include <string>\n#include <vector>\n\nstatic void basic_test()\n{\n\tstd::array<int, 5> A;\n\tstd::array<int, 5> B;\n\n\tsg14::ring_span<int> Q(std::begin(A), std::end(A));\n\n\tQ.push_back(7);\n\tQ.push_back(3);\n\tassert(Q.size() == 2);\n\tassert(Q.front() == 7);\n\n\tQ.pop_front();\n\tassert(Q.size() == 1);\n\n\tQ.push_back(18);\n\tauto Q3 = std::move(Q);\n\tassert(Q3.front() == 3);\n\tassert(Q3.back() == 18);\n\n\tsg14::ring_span<int> Q5(std::move(Q3));\n\tassert(Q5.front() == 3);\n\tassert(Q5.back() == 18);\n\tassert(Q5.size() == 2);\n\n\tQ5.pop_front();\n\tQ5.pop_front();\n\tassert(Q5.empty());\n\n\tsg14::ring_span<int> Q6(std::begin(B), std::end(B));\n\tQ6.push_back(6);\n\tQ6.push_back(7);\n\tQ6.push_back(8);\n\tQ6.push_back(9);\n\tQ6.emplace_back(10);\n\tQ6.swap(Q5);\n\tassert(Q6.empty());\n\tassert(Q5.size() == 5);\n\tassert(Q5.front() == 6);\n\tassert(Q5.back() == 10);\n}\n\nstatic void filter_test()\n{\n\tstd::array< double, 3 > A;\n\tsg14::ring_span< double > buffer( std::begin( A ), std::end( A ) );\n\n\tbuffer.push_back( 1.0 );\n\tbuffer.push_back( 2.0 );\n\tbuffer.push_back( 3.0 );\n\tbuffer.push_back( 5.0 );\n\n\tassert( buffer.front() == 2.0 );\n\n\tconstexpr std::array< double, 3 > filter_coefficients = {{ 0.25, 0.5, 0.25 }};\n\n\t// In an update loop, interrupt routine or the like\n\tbuffer.push_back( 7.0 );\n\n\tassert( std::inner_product( buffer.begin(), buffer.end(), filter_coefficients.begin(), 0.0 ) == 5.0 );\n}\n\nstatic void iterator_regression_test()\n{\n    std::array<double, 3> A;\n    sg14::ring_span<double> r(A.begin(), A.end());\n    r.push_back(1.0);\n    decltype(r)::iterator it = r.end();\n    decltype(r)::const_iterator cit = r.end();  // test conversion from non-const to const\n    assert(it == cit);  // test comparison of const and non-const\n    assert(it + 0 == it);\n    assert(it - 1 == r.begin());\n    assert(cit + 0 == cit);\n    assert(cit - 1 == r.cbegin());\n    assert(it - cit == 0);\n    assert(cit - r.begin() == 1);\n\n    std::array<double, 4> B;\n    sg14::ring_span<double> r2(B.begin(), B.end());\n    swap(r, r2);  // test existence of ADL swap()\n\n    // Set up the ring for the TEST_OP tests below.\n    r = sg14::ring_span<double>(A.begin(), A.end(), A.begin(), 2);\n    assert(r.size() == 2);\n\n#define TEST_OP(op, a, b, c) \\\n    assert(a(r.begin() op r.end())); \\\n    assert(b(r.end() op r.begin())); \\\n    assert(c(r.begin() op r.begin()))\n#define _\n    TEST_OP(==, !, !, _);\n    TEST_OP(!=, _, _, !);\n    TEST_OP(<, _, !, !);\n    TEST_OP(<=, _, !, _);\n    TEST_OP(>, !, _, !);\n    TEST_OP(>=, !, _, _);\n#undef _\n#undef TEST_OP\n}\n\nstatic void copy_popper_test()\n{\n    std::vector<std::string> v { \"quick\", \"brown\", \"fox\" };\n    sg14::ring_span<std::string, sg14::copy_popper<std::string>> r(v.begin(), v.end(), {\"popped\"});\n    r.emplace_back(\"slow\");\n    assert((v == std::vector<std::string>{\"slow\", \"brown\", \"fox\"}));\n    r.emplace_back(\"red\");\n    assert((v == std::vector<std::string>{\"slow\", \"red\", \"fox\"}));\n    std::string result = r.pop_front();\n    assert((v == std::vector<std::string>{\"popped\", \"red\", \"fox\"}));\n    assert(result == \"slow\");\n}\n\nstatic void reverse_iterator_test()\n{\n    std::array<int, 3> A;\n    sg14::ring_span<int> r(A.begin(), A.end());\n    const sg14::ring_span<int> c(A.begin(), A.end());\n\n    r.push_back(1);\n    r.push_back(2);\n    r.push_back(3);\n    r.push_back(4);\n    std::vector<double> v(3);\n\n    std::copy(r.begin(), r.end(), v.begin());\n    assert((v == std::vector<double>{2,3,4}));\n\n    std::copy(r.cbegin(), r.cend(), v.begin());\n    assert((v == std::vector<double>{2,3,4}));\n\n    std::copy(r.rbegin(), r.rend(), v.begin());\n    assert((v == std::vector<double>{4,3,2}));\n\n    std::copy(r.crbegin(), r.crend(), v.begin());\n    assert((v == std::vector<double>{4,3,2}));\n\n    static_assert(std::is_same<decltype(r.begin()), decltype(r)::iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.begin()), decltype(r)::const_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(r.cbegin()), decltype(r)::const_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.cbegin()), decltype(r)::const_iterator>::value, \"\");\n\n    static_assert(std::is_same<decltype(r.end()), decltype(r)::iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.end()), decltype(r)::const_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(r.cend()), decltype(r)::const_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.cend()), decltype(r)::const_iterator>::value, \"\");\n\n    static_assert(std::is_same<decltype(r.rbegin()), decltype(r)::reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.rbegin()), decltype(r)::const_reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(r.crbegin()), decltype(r)::const_reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.crbegin()), decltype(r)::const_reverse_iterator>::value, \"\");\n\n    static_assert(std::is_same<decltype(r.rend()), decltype(r)::reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.rend()), decltype(r)::const_reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(r.crend()), decltype(r)::const_reverse_iterator>::value, \"\");\n    static_assert(std::is_same<decltype(c.crend()), decltype(r)::const_reverse_iterator>::value, \"\");\n}\n\nvoid sg14_test::ring_test()\n{\n    basic_test();\n    filter_test();\n    iterator_regression_test();\n    copy_popper_test();\n    reverse_iterator_test();\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::ring_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/slot_map_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include \"slot_map.h\"\n#include <assert.h>\n#include <inttypes.h>\n#include <algorithm>\n#include <deque>\n#include <forward_list>\n#include <list>\n#include <iterator>\n#include <memory>\n#include <random>\n#include <type_traits>\n#include <utility>\n\nnamespace TestKey {\nstruct key_16_8_t {\n    uint16_t index;\n    uint8_t generation;\n};\nstruct key_11_5_t {  // C++17 only\n    uint16_t index : 11;\n    uint8_t generation : 5;\n};\n\n#if __cplusplus < 201703L\ntemplate<int I, class K> auto get(const K& k) { return get(k, std::integral_constant<int, I>{}); }\ntemplate<int I, class K> auto& get(K& k) { return get(k, std::integral_constant<int, I>{}); }\n\nconst uint16_t& get(const key_16_8_t& k, std::integral_constant<int, 0>) { return k.index; }\nconst uint8_t& get(const key_16_8_t& k, std::integral_constant<int, 1>) { return k.generation; }\nuint16_t& get(key_16_8_t& k, std::integral_constant<int, 0>) { return k.index; }\nuint8_t& get(key_16_8_t& k, std::integral_constant<int, 1>) { return k.generation; }\n#endif // __cplusplus < 201703L\n} // namespace TestKey\n\nnamespace TestContainer {\n\ntemplate<class T>\nstruct Vector {\n    using value_type = T;\n    using reference = T&;\n    using const_reference = const T&;\n    using pointer = T*;\n    using const_pointer = const T*;\n    using size_type = unsigned;\n    using iterator = T*;\n    using const_iterator = const T*;\n    using reverse_iterator = std::reverse_iterator<T*>;\n    using const_reverse_iterator = std::reverse_iterator<const T*>;\n\n    Vector() = default;\n    template<class T_ = T, class = std::enable_if_t<std::is_copy_constructible<T_>::value>>\n    Vector(const Vector& rhs) { *this = rhs; }\n    Vector(Vector&& rhs) { *this = std::move(rhs); }\n    template<class T_ = T, class = std::enable_if_t<std::is_copy_constructible<T_>::value>>\n    void operator=(const Vector& rhs) {\n        size_ = rhs.size_;\n        data_ = std::make_unique<T[]>(size_);\n        std::copy(rhs.begin(), rhs.end(), data_.get());\n    }\n    void operator=(Vector&& rhs) {\n        size_ = rhs.size_;\n        data_ = std::move(rhs.data_);\n    }\n    unsigned size() const { return static_cast<unsigned int>(size_); }\n    T *begin() { return data_.get(); }\n    T *end() { return data_.get() + size_; }\n    const T *begin() const { return data_.get(); }\n    const T *end() const { return data_.get() + size_; }\n    void pop_back() {\n        auto p = std::make_unique<T[]>(size_ - 1);\n        std::move(begin(), end() - 1, p.get());\n        size_ -= 1;\n        data_ = std::move(p);\n    }\n    template<class U, class = std::enable_if_t<std::is_same<U, T>::value>>\n    void emplace_back(U t) {\n        auto p = std::make_unique<T[]>(size_ + 1);\n        std::move(begin(), end(), p.get());\n        size_ += 1;\n        data_ = std::move(p);\n        *(end() - 1) = std::move(t);\n    }\n    void clear() {\n        size_ = 0;\n        data_ = nullptr;\n    }\n    friend void swap(Vector& a, Vector& b) {\n        std::swap(a.size_, b.size_);\n        std::swap(a.data_, b.data_);\n    }\nprivate:\n    size_t size_ = 0;\n    std::unique_ptr<T[]> data_ = nullptr;\n};\n\n} // namespace TestContainer\n\ntemplate<class T_>\nstruct Monad {\n    using T = T_;\n    static T value_of(const T& i) { return i; }\n    template<class U> static T from_value(const U& v) { return static_cast<T>(v); }\n};\ntemplate<class T_>\nstruct Monad<std::unique_ptr<T_>> {\n    using T = std::unique_ptr<T_>;\n    static T_ value_of(const T& ptr) { return *ptr; }\n    template<class U> static T from_value(const U& v) { return std::make_unique<T_>(v); }\n};\n\ntemplate<class T, class Key, template<class...> class Container>\nvoid print_slot_map(const stdext::slot_map<T, Key, Container>& sm)\n{\n    printf(\"%d slots:\", (int)sm.slots_.size());\n    for (auto&& slot : sm.slots_) {\n        printf(\" %d/%d\", (int)slot.first, (int)slot.second);\n    }\n    printf(\"\\n%d values:\", (int)sm.values_.size());\n    for (auto&& value : sm) {\n        printf(\" %d\", (int)value);\n    }\n    assert(sm.reverse_map_.size() == sm.size());\n    printf(\"\\n%d reverse_map:\", (int)sm.reverse_map_.size());\n    for (auto&& idx : sm.reverse_map_) {\n        printf(\" %d\", (int)idx);\n    }\n    printf(\"\\nnext_available_slot_index: %d\\n\", (int)sm.next_available_slot_index_);\n}\n\n\ntemplate<class T, class U = std::conditional_t<std::is_copy_constructible<T>::value, const T&, T&&>>\nstatic U move_if_necessary(T& value) { return static_cast<U>(value); }\n\ntemplate<class SM, class T>\nstatic void BasicTests(T t1, T t2)\n{\n    SM sm;\n    assert(sm.empty());\n    assert(sm.size() == 0);\n    SM sm2 = move_if_necessary(sm);\n    assert(sm2.empty());\n    assert(sm2.size() == 0);\n    auto k1 = sm.insert(std::move(t1));\n    auto k2 = sm.insert(move_if_necessary(t2));\n    assert(!sm.empty());\n    assert(sm.size() == 2);\n    assert(std::next(sm.begin(), 2) == sm.end());\n    assert(sm.find(k1) == sm.begin());\n    assert(sm.find(k2) == std::next(sm.begin()));\n    assert(sm2.empty());\n    assert(sm2.size() == 0);\n    auto num_removed = sm.erase(k1);\n    assert(num_removed == 1);\n    assert(sm.size() == 1);\n    assert(sm.find(k1) == sm.end());  // find an expired key\n    try { (void)sm.at(k1); assert(false); } catch (const std::out_of_range&) {}\n    assert(sm.find(k2) == sm.begin());  // find a non-expired key\n    assert(sm.at(k2) == *sm.begin());\n    assert(sm.find_unchecked(k2) == sm.begin());\n    assert(sm[k2] == *sm.begin());\n    assert(sm.erase(k1) == 0);  // erase an expired key\n    sm.swap(sm2);\n    assert(sm.empty());\n    assert(sm2.size() == 1);\n    assert(sm2.find(k1) == sm2.end());  // find an expired key\n    assert(sm2.find(k2) == sm2.begin());  // find a non-expired key\n    assert(sm2.erase(k1) == 0);  // erase an expired key\n}\n\ntemplate<class SM, class TGen>\nstatic void FullContainerStressTest(TGen t)\n{\n    const int total = 1000;\n    SM sm;\n    std::vector<typename SM::key_type> keys;\n    for (int i=0; i < total; ++i) {\n        auto k = sm.insert(t());\n        keys.push_back(k);\n    }\n    assert(sm.size() == total);\n    std::mt19937 g;\n    std::shuffle(keys.begin(), keys.end(), g);\n    for (int i = 0; i < total; ++i) {\n        assert(sm.size() == static_cast<typename SM::size_type>(total - i));\n        assert(sm.find(keys[i]) != sm.end());\n        assert(sm.find_unchecked(keys[i]) != sm.end());\n        for (int j = 0; j < i; ++j) {\n            assert(sm.find(keys[j]) == sm.end());\n        }\n        auto erased = sm.erase(keys[i]);\n        assert(erased == 1);\n    }\n    assert(sm.empty());\n}\n\ntemplate<class SM, class TGen>\nstatic void InsertEraseStressTest(TGen t)\n{\n    const int total = 1000;\n    SM sm;\n    std::vector<typename SM::key_type> valid_keys;\n    std::vector<typename SM::key_type> expired_keys;\n    std::mt19937 g;\n    for (int i=0; i < total / 3; ++i) {\n        auto k = sm.insert(t());\n        valid_keys.push_back(k);\n    }\n    for (int i = total / 3; i < total; ++i) {\n        if (g() % 2 == 0 && !valid_keys.empty()) {\n            std::shuffle(valid_keys.begin(), valid_keys.end(), g);\n            auto k = valid_keys.back();\n            valid_keys.pop_back();\n            auto erased = sm.erase(k);\n            assert(erased == 1);\n            expired_keys.push_back(k);\n            for (auto&& ek : expired_keys) {\n                assert(sm.find(ek) == sm.end());\n            }\n        } else {\n            auto k = sm.insert(t());\n            valid_keys.push_back(k);\n        }\n    }\n}\n\ntemplate<class SM>\nstatic void EraseInLoopTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    for (int i=0; i < 100; ++i) {\n        sm.insert(Monad<T>::from_value(i));\n    }\n    int total = 0;\n    for (auto it = sm.begin(); it != sm.end(); /*nothing*/) {\n        total += Monad<T>::value_of(*it);\n        if (Monad<T>::value_of(*it) > 50) {\n            it = sm.erase(it);\n        } else {\n            ++it;\n        }\n    }\n    assert(total == 4950);\n    int total2 = 0;\n    for (auto&& elt : sm) {\n        total2 += Monad<T>::value_of(elt);\n    }\n    assert(total2 == 1275);\n}\n\ntemplate<class SM>\nstatic void EraseRangeTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    auto test = [&](int N, int first, int last) {\n        sm.erase(sm.begin(), sm.end());\n        int expected_total = 0;\n        for (int i=0; i < N; ++i) {\n            expected_total += i;\n            sm.insert(Monad<T>::from_value(i));\n        }\n        for (auto it = std::next(sm.begin(), first); it != std::next(sm.begin(), last); ++it) {\n            expected_total -= Monad<T>::value_of(*it);\n        }\n        sm.erase(std::next(sm.begin(), first), std::next(sm.begin(), last));\n        int actual_total = 0;\n        for (auto it = sm.begin(); it != sm.end(); ++it) {\n            actual_total += Monad<T>::value_of(*it);\n        }\n        return (actual_total == expected_total);\n    };\n    assert(test(10, 8, 8));\n    assert(test(10, 3, 7));\n    assert(test(10, 0, 10));\n    assert(test(10, 1, 10));\n    assert(test(10, 0, 9));\n    assert(test(10, 1, 9));\n    for (int N : { 2, 10, 100 }) {\n        for (int i=0; i < N; ++i) {\n            for (int j=i; j < N; ++j) {\n                assert(test(N, i, j));\n            }\n        }\n    }\n}\n\ntemplate<class SM>\nstatic void ReserveTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    auto k = sm.emplace(Monad<T>::from_value(1));\n    (void)k;\n    assert(sm.size() == 1);\n\n    auto original_cap = sm.slot_count();\n    static_assert(std::is_same<decltype(original_cap), typename SM::size_type>::value, \"\");\n    assert(original_cap >= 1);\n\n    sm.reserve_slots(original_cap + 3);\n    assert(sm.slot_count() >= original_cap + 3);\n    assert(sm.size() == 1);\n\n    sm.emplace(Monad<T>::from_value(2));\n    sm.emplace(Monad<T>::from_value(3));\n    sm.emplace(Monad<T>::from_value(4));\n    assert(sm.size() == 4);\n}\n\ntemplate<class SM, class = decltype(std::declval<const SM&>().capacity())>\nstatic void VerifyCapacityExists(bool expected)\n{\n    assert(expected);\n    SM sm;\n    auto n = sm.capacity();\n    static_assert(std::is_same<decltype(n), typename SM::size_type>::value, \"\");\n    assert(n == 0);\n    sm.reserve(100);\n    assert(sm.capacity() >= 100);\n    assert(sm.slot_count() >= 100);\n}\n\ntemplate<class SM, class Bool>\nvoid VerifyCapacityExists(Bool expected)\n{\n    assert(!expected);\n    SM sm;\n    sm.reserve(100);\n    assert(sm.slot_count() >= 100);\n}\n\nstatic void TypedefTests()\n{\n    if (true) {\n        using SM = stdext::slot_map<int>;\n        static_assert(std::is_same<typename SM::key_type, std::pair<unsigned, unsigned>>::value, \"\");\n        static_assert(std::is_same<typename SM::mapped_type, int>::value, \"\");\n        static_assert(std::is_same<typename SM::key_index_type, unsigned>::value, \"\");\n        static_assert(std::is_same<typename SM::key_generation_type, unsigned>::value, \"\");\n        static_assert(std::is_same<typename SM::container_type, std::vector<int>>::value, \"\");\n        static_assert(std::is_same<typename SM::reference, int&>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reference, const int&>::value, \"\");\n        static_assert(std::is_same<typename SM::pointer, int*>::value, \"\");\n        static_assert(std::is_same<typename SM::const_pointer, const int*>::value, \"\");\n        static_assert(std::is_same<typename SM::iterator, std::vector<int>::iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_iterator, std::vector<int>::const_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::reverse_iterator, std::vector<int>::reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reverse_iterator, std::vector<int>::const_reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::size_type, std::vector<int>::size_type>::value, \"\");\n        static_assert(std::is_same<typename SM::value_type, int>::value, \"\");\n    }\n    if (true) {\n        using SM = stdext::slot_map<bool>;\n        static_assert(std::is_same<typename SM::key_type, std::pair<unsigned, unsigned>>::value, \"\");\n        static_assert(std::is_same<typename SM::mapped_type, bool>::value, \"\");\n        static_assert(std::is_same<typename SM::key_index_type, unsigned>::value, \"\");\n        static_assert(std::is_same<typename SM::key_generation_type, unsigned>::value, \"\");\n        static_assert(std::is_same<typename SM::container_type, std::vector<bool>>::value, \"\");\n        static_assert(std::is_same<typename SM::reference, std::vector<bool>::reference>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reference, std::vector<bool>::const_reference>::value, \"\");\n        static_assert(std::is_same<typename SM::pointer, std::vector<bool>::pointer>::value, \"\");\n        static_assert(std::is_same<typename SM::const_pointer, std::vector<bool>::const_pointer>::value, \"\");\n        static_assert(std::is_same<typename SM::iterator, std::vector<bool>::iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_iterator, std::vector<bool>::const_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::reverse_iterator, std::vector<bool>::reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reverse_iterator, std::vector<bool>::const_reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::size_type, std::vector<bool>::size_type>::value, \"\");\n        static_assert(std::is_same<typename SM::value_type, bool>::value, \"\");\n    }\n    if (true) {\n        using SM = stdext::slot_map<double, TestKey::key_16_8_t>;\n        static_assert(std::is_same<typename SM::key_type, TestKey::key_16_8_t>::value, \"\");\n        static_assert(std::is_same<typename SM::mapped_type, double>::value, \"\");\n        static_assert(std::is_same<typename SM::key_index_type, uint16_t>::value, \"\");\n        static_assert(std::is_same<typename SM::key_generation_type, uint8_t>::value, \"\");\n        static_assert(std::is_same<typename SM::container_type, std::vector<double>>::value, \"\");\n        static_assert(std::is_same<typename SM::reference, double&>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reference, const double&>::value, \"\");\n        static_assert(std::is_same<typename SM::pointer, double*>::value, \"\");\n        static_assert(std::is_same<typename SM::const_pointer, const double*>::value, \"\");\n        static_assert(std::is_same<typename SM::iterator, std::vector<double>::iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_iterator, std::vector<double>::const_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::reverse_iterator, std::vector<double>::reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reverse_iterator, std::vector<double>::const_reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::size_type, std::vector<double>::size_type>::value, \"\");\n        static_assert(std::is_same<typename SM::value_type, double>::value, \"\");\n    }\n    if (true) {\n        using SM = stdext::slot_map<int, std::pair<char, int>, TestContainer::Vector>;\n        static_assert(std::is_same<typename SM::key_type, std::pair<char, int>>::value, \"\");\n        static_assert(std::is_same<typename SM::mapped_type, int>::value, \"\");\n        static_assert(std::is_same<typename SM::key_index_type, char>::value, \"\");\n        static_assert(std::is_same<typename SM::key_generation_type, int>::value, \"\");\n        static_assert(std::is_same<typename SM::container_type, TestContainer::Vector<int>>::value, \"\");\n        static_assert(std::is_same<typename SM::reference, int&>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reference, const int&>::value, \"\");\n        static_assert(std::is_same<typename SM::pointer, int*>::value, \"\");\n        static_assert(std::is_same<typename SM::const_pointer, const int*>::value, \"\");\n        static_assert(std::is_same<typename SM::iterator, TestContainer::Vector<int>::iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_iterator, TestContainer::Vector<int>::const_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::reverse_iterator, TestContainer::Vector<int>::reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reverse_iterator, TestContainer::Vector<int>::const_reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::size_type, unsigned>::value, \"\");\n        static_assert(std::is_same<typename SM::value_type, int>::value, \"\");\n    }\n#if __cplusplus >= 201703L\n    if (true) {\n        using SM = stdext::slot_map<double, TestKey::key_11_5_t>;\n        static_assert(std::is_same<typename SM::key_type, TestKey::key_11_5_t>::value, \"\");\n        static_assert(std::is_same<typename SM::mapped_type, double>::value, \"\");\n        static_assert(std::is_same<typename SM::key_index_type, uint16_t>::value, \"\");\n        static_assert(std::is_same<typename SM::key_generation_type, uint8_t>::value, \"\");\n        static_assert(std::is_same<typename SM::container_type, std::vector<double>>::value, \"\");\n        static_assert(std::is_same<typename SM::reference, double&>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reference, const double&>::value, \"\");\n        static_assert(std::is_same<typename SM::pointer, double*>::value, \"\");\n        static_assert(std::is_same<typename SM::const_pointer, const double*>::value, \"\");\n        static_assert(std::is_same<typename SM::iterator, std::vector<double>::iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_iterator, std::vector<double>::const_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::reverse_iterator, std::vector<double>::reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::const_reverse_iterator, std::vector<double>::const_reverse_iterator>::value, \"\");\n        static_assert(std::is_same<typename SM::size_type, std::vector<double>::size_type>::value, \"\");\n        static_assert(std::is_same<typename SM::value_type, double>::value, \"\");\n    }\n#endif // __cplusplus >= 201703L\n}\n\ntemplate<class SM>\nvoid BoundsCheckingTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    const auto& csm = sm;\n\n    sm.emplace(Monad<T>::from_value(1));\n    typename SM::key_type k = sm.emplace(Monad<T>::from_value(2));\n    sm.clear();\n\n    typename SM::iterator it = sm.find(k);\n    assert(it == sm.end());\n\n    typename SM::const_iterator cit = csm.find(k);\n    assert(cit == sm.end());\n}\n\ntemplate<class SM>\nstatic void GenerationsDontSkipTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    auto k1 = sm.emplace(Monad<T>::from_value(1));\n    int original_cap = static_cast<int>(sm.slot_count());\n    for (int i=1; i < original_cap; ++i) {\n        sm.emplace(Monad<T>::from_value(i));\n    }\n    assert(sm.size() == sm.slot_count());\n\n    sm.erase(k1);\n    auto k2 = sm.emplace(Monad<T>::from_value(2));\n\n#if __cplusplus < 201703L\n    using std::get;\n    assert(get<0>(k2) == get<0>(k1));\n    assert(get<1>(k2) == get<1>(k1) + 1);\n#else\n    auto [idx1, gen1] = k1;\n    auto [idx2, gen2] = k2;\n    assert(idx2 == idx1);\n    assert(gen2 == gen1 + 1);\n#endif\n}\n\ntemplate<class SM>\nstatic void IndexesAreUsedEvenlyTest()\n{\n    using T = typename SM::mapped_type;\n    SM sm;\n    auto k1 = sm.emplace(Monad<T>::from_value(1));\n    auto k2 = sm.emplace(Monad<T>::from_value(2));\n    int original_cap = static_cast<int>(sm.slot_count());\n    for (int i=2; i < original_cap; ++i) {\n        sm.emplace(Monad<T>::from_value(i));\n    }\n    assert(sm.size() == sm.slot_count());\n\n    sm.erase(k1);\n    sm.erase(k2);\n    assert(sm.size() == sm.slot_count() - 2);\n\n    // There are now two slots available.\n    // So consecutive insertions should prefer to\n    // use different slots, rather than sticking to\n    // just one slot and bumping its generation count.\n    k1 = sm.emplace(Monad<T>::from_value(1));\n    sm.erase(k1);\n    k2 = sm.emplace(Monad<T>::from_value(2));\n    sm.erase(k2);\n\n#if __cplusplus < 201703L\n    using std::get;\n    assert(get<0>(k2) != get<0>(k1));\n#else\n    auto [idx1, gen1] = k1;\n    auto [idx2, gen2] = k2;\n    assert(idx2 != idx1);\n#endif\n}\n\nvoid sg14_test::slot_map_test()\n{\n    TypedefTests();\n\n    // Test the most basic slot_map.\n    using slot_map_1 = stdext::slot_map<int>;\n    static_assert(std::is_nothrow_move_constructible<slot_map_1>::value, \"preserve nothrow-movability of vector\");\n    BasicTests<slot_map_1>(42, 37);\n    BoundsCheckingTest<slot_map_1>();\n    FullContainerStressTest<slot_map_1>([]() { return 1; });\n    InsertEraseStressTest<slot_map_1>([i=3]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_1>();\n    EraseRangeTest<slot_map_1>();\n    ReserveTest<slot_map_1>();\n    VerifyCapacityExists<slot_map_1>(true);\n    GenerationsDontSkipTest<slot_map_1>();\n    IndexesAreUsedEvenlyTest<slot_map_1>();\n\n    // Test slot_map with a custom key type (C++14 destructuring).\n    using slot_map_2 = stdext::slot_map<unsigned long, TestKey::key_16_8_t>;\n    BasicTests<slot_map_2>(425, 375);\n    BoundsCheckingTest<slot_map_2>();\n    FullContainerStressTest<slot_map_2>([]() { return 42; });\n    InsertEraseStressTest<slot_map_2>([i=5]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_2>();\n    EraseRangeTest<slot_map_2>();\n    ReserveTest<slot_map_2>();\n    VerifyCapacityExists<slot_map_2>(true);\n    GenerationsDontSkipTest<slot_map_2>();\n    IndexesAreUsedEvenlyTest<slot_map_2>();\n\n#if __cplusplus >= 201703L\n    // Test slot_map with a custom key type (C++17 destructuring).\n    using slot_map_3 = stdext::slot_map<int, TestKey::key_11_5_t>;\n    BasicTests<slot_map_3>(42, 37);\n    BoundsCheckingTest<slot_map_3>();\n    FullContainerStressTest<slot_map_3>([]() { return 42; });\n    InsertEraseStressTest<slot_map_3>([i=3]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_3>();\n    EraseRangeTest<slot_map_3>();\n    ReserveTest<slot_map_3>();\n    VerifyCapacityExists<slot_map_3>(true);\n    GenerationsDontSkipTest<slot_map_3>();\n    IndexesAreUsedEvenlyTest<slot_map_3>();\n#endif // __cplusplus >= 201703L\n\n    // Test slot_map with a custom (but standard and random-access) container type.\n    using slot_map_4 = stdext::slot_map<int, std::pair<unsigned, unsigned>, std::deque>;\n    BasicTests<slot_map_4>(415, 315);\n    BoundsCheckingTest<slot_map_4>();\n    FullContainerStressTest<slot_map_4>([]() { return 37; });\n    InsertEraseStressTest<slot_map_4>([i=7]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_4>();\n    EraseRangeTest<slot_map_4>();\n    ReserveTest<slot_map_4>();\n    VerifyCapacityExists<slot_map_4>(false);\n    GenerationsDontSkipTest<slot_map_4>();\n    IndexesAreUsedEvenlyTest<slot_map_4>();\n\n    // Test slot_map with a custom (non-standard, random-access) container type.\n    using slot_map_5 = stdext::slot_map<int, std::pair<unsigned, unsigned>, TestContainer::Vector>;\n    static_assert(!std::is_nothrow_move_constructible<slot_map_5>::value, \"preserve non-nothrow-movability of Vector\");\n    BasicTests<slot_map_5>(415, 315);\n    BoundsCheckingTest<slot_map_5>();\n    FullContainerStressTest<slot_map_5>([]() { return 37; });\n    InsertEraseStressTest<slot_map_5>([i=7]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_5>();\n    EraseRangeTest<slot_map_5>();\n    ReserveTest<slot_map_5>();\n    VerifyCapacityExists<slot_map_5>(false);\n    GenerationsDontSkipTest<slot_map_5>();\n    IndexesAreUsedEvenlyTest<slot_map_5>();\n\n    // Test slot_map with a custom (standard, bidirectional-access) container type.\n    using slot_map_6 = stdext::slot_map<int, std::pair<unsigned, unsigned>, std::list>;\n    static_assert(std::is_nothrow_move_constructible<slot_map_6>::value == std::is_nothrow_move_constructible<std::list<int>>::value,\n                  \"preserve implementation-defined nothrow-movability of std::list\");\n    BasicTests<slot_map_6>(415, 315);\n    BoundsCheckingTest<slot_map_6>();\n    FullContainerStressTest<slot_map_6>([]() { return 37; });\n    InsertEraseStressTest<slot_map_6>([i=7]() mutable { return ++i; });\n    EraseInLoopTest<slot_map_6>();\n    EraseRangeTest<slot_map_6>();\n    ReserveTest<slot_map_6>();\n    VerifyCapacityExists<slot_map_6>(false);\n    GenerationsDontSkipTest<slot_map_6>();\n    IndexesAreUsedEvenlyTest<slot_map_6>();\n\n    // Test slot_map with a move-only value_type.\n    // Sadly, standard containers do not propagate move-only-ness, so we must use our custom Vector instead.\n    using slot_map_7 = stdext::slot_map<std::unique_ptr<int>, std::pair<unsigned, int>, TestContainer::Vector>;\n    static_assert(std::is_move_constructible<slot_map_7>::value, \"\");\n    static_assert(std::is_move_assignable<slot_map_7>::value, \"\");\n    static_assert(! std::is_copy_constructible<slot_map_7>::value, \"\");\n    static_assert(! std::is_copy_assignable<slot_map_7>::value, \"\");\n    BasicTests<slot_map_7>(std::make_unique<int>(1), std::make_unique<int>(2));\n    BoundsCheckingTest<slot_map_7>();\n    FullContainerStressTest<slot_map_7>([]() { return std::make_unique<int>(1); });\n    InsertEraseStressTest<slot_map_7>([i=7]() mutable { return std::make_unique<int>(++i); });\n    EraseInLoopTest<slot_map_7>();\n    EraseRangeTest<slot_map_7>();\n    ReserveTest<slot_map_7>();\n    VerifyCapacityExists<slot_map_7>(false);\n    GenerationsDontSkipTest<slot_map_7>();\n    IndexesAreUsedEvenlyTest<slot_map_7>();\n}\n\n#if defined(__cpp_concepts)\ntemplate<template<class...> class Ctr, class T = int>\nconcept bool SlotMapContainer =\n    requires(Ctr<T> c, const Ctr<T> cc, T t) {\n        { Ctr<T>{} };  // default constructible, destructible\n        { Ctr<T>(cc) };  // copy constructible\n        { Ctr<T>(static_cast<Ctr<T>&&>(c)) };  // move constructible\n        { c = cc };  // copy assignable\n        { c = static_cast<Ctr<T>&&>(c) };  // move assignable\n        typename Ctr<T>::value_type;\n        typename Ctr<T>::size_type;\n        typename Ctr<T>::reference;\n        typename Ctr<T>::const_reference;\n        typename Ctr<T>::pointer;\n        typename Ctr<T>::const_pointer;\n        typename Ctr<T>::iterator;\n        typename Ctr<T>::const_iterator;\n        typename Ctr<T>::reverse_iterator;\n        typename Ctr<T>::const_reverse_iterator;\n        { c.emplace_back(t) };\n        { c.pop_back() };\n        { c.begin() } -> typename Ctr<T>::iterator;\n        { c.end() } -> typename Ctr<T>::iterator;\n        { cc.size() } -> typename Ctr<T>::size_type;\n        { cc.begin() } -> typename Ctr<T>::const_iterator;\n        { cc.end() } -> typename Ctr<T>::const_iterator;\n        { std::next(c.begin()) } -> typename Ctr<T>::iterator;\n        { std::next(cc.begin()) } -> typename Ctr<T>::const_iterator;\n    };\nstatic_assert(SlotMapContainer<std::vector>);\nstatic_assert(SlotMapContainer<std::deque>);\nstatic_assert(SlotMapContainer<std::list>);\nstatic_assert(not SlotMapContainer<std::forward_list>);\nstatic_assert(not SlotMapContainer<std::pair>);\n#endif  // defined(__cpp_concepts)\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::slot_map_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/uninitialized_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include <vector>\n#include <array>\n#include <ctime>\n#include <iostream>\n#include <algorithm>\n#include \"algorithm_ext.h\"\n#include <cassert>\n#include <memory>\n\nnamespace\n{\n\tstruct lifetest\n\t{\n\t\tstatic uint64_t construct;\n\t\tstatic uint64_t destruct;\n\t\tstatic uint64_t move;\n\t\tlifetest()\n\t\t{\n\t\t\t++construct;\n\t\t}\n\t\tlifetest(lifetest&& /*in*/) noexcept\n\t\t{\n\t\t\t++move;\n\t\t}\n\t\t~lifetest()\n\t\t{\n\t\t\t++destruct;\n\t\t}\n\t\tstatic void reset()\n\t\t{\n\t\t\tconstruct = 0;\n\t\t\tdestruct = 0;\n\t\t\tmove = 0;\n\t\t}\n\n\t\t// To avoid \"unused argument\" error/warning. \n\t\t#ifdef NDEBUG\n\t\t\tstatic void test(uint64_t, uint64_t, uint64_t)\n\t\t\t{\n\t\t\t\t\n\t\t\t}\n\t\t#else\n\t\t\tstatic void test(uint64_t inconstruct, uint64_t indestruct, uint64_t inmove)\n\t\t\t{\n\t\t\t\tassert(construct == inconstruct);\n\t\t\t\tassert(destruct == indestruct);\n\t\t\t\tassert(move == inmove);\n\t\t\t}\n\t\t#endif\n\t\t\n\t};\n\tuint64_t lifetest::construct;\n\tuint64_t lifetest::destruct;\n\tuint64_t lifetest::move;\n\n\tvoid value()\n\t{\n\t\tfor (auto n = 0; n < 256; ++n)\n\t\t{\n\t\t\tauto m = (lifetest*)malloc(sizeof(lifetest) * n);\n\t\t\tlifetest::test(0, 0, 0);\n\t\t\tstdext::uninitialized_value_construct(m, m + n);\n\t\t\tlifetest::test(n, 0, 0);\n\t\t\tstdext::destruct(m, m + n);\n\t\t\tlifetest::test(n, n, 0);\n\t\t\tfree(m);\n\t\t\tlifetest::reset();\n\t\t}\n\n\t\tauto m = (int*)malloc(sizeof(int) * 5);\n\t\tstdext::uninitialized_value_construct(m, m + 5);\n\t\tassert(std::all_of(m, m + 5, [](int x) { return x == 0; }));\n\t\tfree(m);\n\t};\n\n\tvoid def()\n\t{\n\t\tfor (auto n = 0; n < 256; ++n)\n\t\t{\n\t\t\tauto mem1 = (lifetest*)malloc(sizeof(lifetest) * n);\n\t\t\tlifetest::test(0, 0, 0);\n\t\t\tstdext::uninitialized_default_construct(mem1, mem1 + n);\n\t\t\tlifetest::test(n, 0, 0);\n\n\t\t\tauto mem2 = (lifetest*)malloc(sizeof(lifetest) * n);\n\t\t\tstdext::uninitialized_move(mem1, mem1 + n, mem2);\n\t\t\tlifetest::test(n, 0, n);\n\t\t\tstdext::destruct(mem2, mem2 + n);\n\t\t\tlifetest::test(n, n, n);\n\t\t\tfree(mem1);\n\t\t\tfree(mem2);\n\t\t\tlifetest::reset();\n\t\t}\n\t}\n}\n\n\n\nvoid sg14_test::uninitialized_test()\n{\n\tvalue();\n\tdef();\n\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::uninitialized_test();\n}\n#endif\n"
  },
  {
    "path": "SG14_test/unstable_remove_test.cpp",
    "content": "#include \"SG14_test.h\"\n#include \"algorithm_ext.h\"\n#include <algorithm>\n#include <array>\n#include <chrono>\n#include <iostream>\n#include <iterator>\n#include <vector>\n\nstruct foo\n{\n    std::array<int,16> info;\n    static foo make()\n    {\n        foo result;\n        std::fill(result.info.begin(), result.info.end(), ::rand());\n        return result;\n    }\n};\n\n\nvoid sg14_test::unstable_remove_test()\n{\n    size_t test_runs = 200;\n\n    auto makelist = []\n    {\n        std::vector<foo> list;\n        std::generate_n(std::back_inserter(list), 30000, foo::make);\n        return list;\n    };\n\n    auto cmp = [](foo& f) {return f.info[0] & 1; };\n\n    auto partitionfn = [&](std::vector<foo>& f)\n    {\n        stdext::partition(f.begin(), f.end(), cmp);\n    };\n    auto unstablefn = [&](std::vector<foo>& f)\n    {\n        stdext::unstable_remove_if(f.begin(), f.end(), cmp);\n    };\n    auto removefn = [&](std::vector<foo>& f)\n    {\n        stdext::remove_if(f.begin(), f.end(), cmp);\n    };\n    auto time = [&](auto&& f)\n    {\n        auto list = makelist();\n        auto t0 = std::chrono::high_resolution_clock::now();\n        f(list);\n        auto t1 = std::chrono::high_resolution_clock::now();\n        return (t1 - t0).count();\n    };\n\n    using time_lambda_t = decltype(time(removefn));\n\n    auto median = [](std::vector<time_lambda_t>& v)\n    {\n        auto b = v.begin();\n        auto e = v.end();\n        return *(b + ((e - b) / 2));\n    };\n\n    std::vector<time_lambda_t> partition;\n    std::vector<time_lambda_t> unstable_remove_if;\n    std::vector<time_lambda_t> remove_if;\n\n    partition.reserve(test_runs);\n    unstable_remove_if.reserve(test_runs);\n    remove_if.reserve(test_runs);\n\n    for (decltype(test_runs) i = 0; i < test_runs; ++i)\n    {\n        remove_if.push_back(time(removefn));\n        unstable_remove_if.push_back(time(unstablefn));\n        partition.push_back(time(partitionfn));\n    }\n    std::sort(partition.begin(), partition.end());\n    std::sort(unstable_remove_if.begin(), unstable_remove_if.end());\n    std::sort(remove_if.begin(), remove_if.end());\n\n    auto partition_med = median(partition);\n    auto unstable_med = median(unstable_remove_if);\n    auto remove_med = median(remove_if);\n\n\n    std::cout << \"partition: \" << partition_med << \"\\n\";\n    std::cout << \"unstable: \" << unstable_med << \"\\n\";\n    std::cout << \"remove_if: \" << remove_med << \"\\n\";\n}\n\n#ifdef TEST_MAIN\nint main()\n{\n    sg14_test::unstable_remove_test();\n}\n#endif\n"
  }
]