summaryrefslogtreecommitdiff
path: root/src/third_party/immer
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /src/third_party/immer
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (diff)
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0' with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/third_party/immer')
-rw-r--r--src/third_party/immer/dist/LICENSE23
-rw-r--r--src/third_party/immer/dist/README.rst224
-rw-r--r--src/third_party/immer/dist/immer/algorithm.hpp325
-rw-r--r--src/third_party/immer/dist/immer/array.hpp375
-rw-r--r--src/third_party/immer/dist/immer/array_transient.hpp204
-rw-r--r--src/third_party/immer/dist/immer/atom.hpp254
-rw-r--r--src/third_party/immer/dist/immer/box.hpp240
-rw-r--r--src/third_party/immer/dist/immer/config.hpp131
-rw-r--r--src/third_party/immer/dist/immer/detail/arrays/no_capacity.hpp211
-rw-r--r--src/third_party/immer/dist/immer/detail/arrays/node.hpp131
-rw-r--r--src/third_party/immer/dist/immer/detail/arrays/with_capacity.hpp317
-rw-r--r--src/third_party/immer/dist/immer/detail/combine_standard_layout.hpp236
-rw-r--r--src/third_party/immer/dist/immer/detail/hamts/bits.hpp175
-rw-r--r--src/third_party/immer/dist/immer/detail/hamts/champ.hpp1548
-rw-r--r--src/third_party/immer/dist/immer/detail/hamts/champ_iterator.hpp151
-rw-r--r--src/third_party/immer/dist/immer/detail/hamts/node.hpp1137
-rw-r--r--src/third_party/immer/dist/immer/detail/iterator_facade.hpp212
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/bits.hpp34
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/node.hpp1033
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/operations.hpp2508
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/position.hpp1994
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/rbtree.hpp534
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/rbtree_iterator.hpp99
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/rrbtree.hpp1450
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/rrbtree_iterator.hpp98
-rw-r--r--src/third_party/immer/dist/immer/detail/rbts/visitor.hpp56
-rw-r--r--src/third_party/immer/dist/immer/detail/ref_count_base.hpp36
-rw-r--r--src/third_party/immer/dist/immer/detail/type_traits.hpp205
-rw-r--r--src/third_party/immer/dist/immer/detail/util.hpp314
-rw-r--r--src/third_party/immer/dist/immer/experimental/detail/dvektor_impl.hpp499
-rw-r--r--src/third_party/immer/dist/immer/experimental/dvektor.hpp71
-rw-r--r--src/third_party/immer/dist/immer/flex_vector.hpp624
-rw-r--r--src/third_party/immer/dist/immer/flex_vector_transient.hpp248
-rw-r--r--src/third_party/immer/dist/immer/heap/cpp_heap.hpp42
-rw-r--r--src/third_party/immer/dist/immer/heap/debug_size_heap.hpp69
-rw-r--r--src/third_party/immer/dist/immer/heap/free_list_heap.hpp84
-rw-r--r--src/third_party/immer/dist/immer/heap/free_list_node.hpp24
-rw-r--r--src/third_party/immer/dist/immer/heap/gc_heap.hpp131
-rw-r--r--src/third_party/immer/dist/immer/heap/heap_policy.hpp140
-rw-r--r--src/third_party/immer/dist/immer/heap/identity_heap.hpp34
-rw-r--r--src/third_party/immer/dist/immer/heap/malloc_heap.hpp46
-rw-r--r--src/third_party/immer/dist/immer/heap/split_heap.hpp41
-rw-r--r--src/third_party/immer/dist/immer/heap/tags.hpp16
-rw-r--r--src/third_party/immer/dist/immer/heap/thread_local_free_list_heap.hpp57
-rw-r--r--src/third_party/immer/dist/immer/heap/unsafe_free_list_heap.hpp111
-rw-r--r--src/third_party/immer/dist/immer/heap/with_data.hpp43
-rw-r--r--src/third_party/immer/dist/immer/lock/no_lock_policy.hpp25
-rw-r--r--src/third_party/immer/dist/immer/lock/spinlock_policy.hpp68
-rw-r--r--src/third_party/immer/dist/immer/map.hpp550
-rw-r--r--src/third_party/immer/dist/immer/map_transient.hpp318
-rw-r--r--src/third_party/immer/dist/immer/memory_policy.hpp142
-rw-r--r--src/third_party/immer/dist/immer/refcount/enable_intrusive_ptr.hpp37
-rw-r--r--src/third_party/immer/dist/immer/refcount/no_refcount_policy.hpp30
-rw-r--r--src/third_party/immer/dist/immer/refcount/refcount_policy.hpp40
-rw-r--r--src/third_party/immer/dist/immer/refcount/unsafe_refcount_policy.hpp37
-rw-r--r--src/third_party/immer/dist/immer/set.hpp295
-rw-r--r--src/third_party/immer/dist/immer/set_transient.hpp184
-rw-r--r--src/third_party/immer/dist/immer/table.hpp547
-rw-r--r--src/third_party/immer/dist/immer/table_transient.hpp281
-rw-r--r--src/third_party/immer/dist/immer/transience/gc_transience_policy.hpp113
-rw-r--r--src/third_party/immer/dist/immer/transience/no_transience_policy.hpp48
-rw-r--r--src/third_party/immer/dist/immer/vector.hpp423
-rw-r--r--src/third_party/immer/dist/immer/vector_transient.hpp200
-rw-r--r--src/third_party/immer/dist/tools/gdb_pretty_printers/__init__.py1
-rw-r--r--src/third_party/immer/dist/tools/gdb_pretty_printers/autoload.py11
-rw-r--r--src/third_party/immer/dist/tools/gdb_pretty_printers/printers.py485
-rwxr-xr-xsrc/third_party/immer/scripts/import.sh49
67 files changed, 0 insertions, 20419 deletions
diff --git a/src/third_party/immer/dist/LICENSE b/src/third_party/immer/dist/LICENSE
deleted file mode 100644
index 36b7cd93cdf..00000000000
--- a/src/third_party/immer/dist/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
diff --git a/src/third_party/immer/dist/README.rst b/src/third_party/immer/dist/README.rst
deleted file mode 100644
index 195065209ad..00000000000
--- a/src/third_party/immer/dist/README.rst
+++ /dev/null
@@ -1,224 +0,0 @@
-.. image:: https://github.com/arximboldi/immer/workflows/test/badge.svg
- :target: https://github.com/arximboldi/immer/actions?query=workflow%3Atest+branch%3Amaster
- :alt: GitHub Actions Badge
-
-.. image:: https://codecov.io/gh/arximboldi/immer/branch/master/graph/badge.svg
- :target: https://codecov.io/gh/arximboldi/immer
- :alt: CodeCov Badge
-
-.. image:: https://cdn.rawgit.com/arximboldi/immer/355a113782aedc2ea22463444014809269c2376d/doc/_static/sinusoidal-badge.svg
- :target: https://sinusoid.al
- :alt: Sinusoidal Engineering badge
- :align: right
-
-.. raw:: html
-
- <img width="100%" src="https://cdn.rawgit.com/arximboldi/immer/3888170d247359cc0905eed548cd46897caef0f4/doc/_static/logo-front.svg" alt="Logotype"/>
-
-.. include:introduction/start
-
-**immer** is a library of persistent_ and immutable_ data structures
-written in C++. These enable whole new kinds of architectures for
-interactive and concurrent programs of striking simplicity,
-correctness, and performance.
-
-.. _persistent: https://en.wikipedia.org/wiki/Persistent_data_structure
-.. _immutable: https://en.wikipedia.org/wiki/Immutable_object
-
-* **Documentation** (Contents_)
-* **Code** (GitHub_)
-* **CppCon'17 Talk**: *Postmodern Immutable Data Structures* (YouTube_, Slides_)
-* **ICFP'17 Paper**: *Persistence for the masses* (Preprint_)
-
-.. _contents: https://sinusoid.es/immer/#contents
-.. _github: https://github.com/arximboldi/immer
-.. _youtube: https://www.youtube.com/watch?v=sPhpelUfu8Q
-.. _slides: https://sinusoid.es/talks/immer-cppcon17
-.. _preprint: https://public.sinusoid.es/misc/immer/immer-icfp17.pdf
-
-
- .. raw:: html
-
- <a href="https://www.patreon.com/sinusoidal">
- <img align="right" src="https://cdn.rawgit.com/arximboldi/immer/master/doc/_static/patreon.svg">
- </a>
-
- This library has full months of *pro bono* research and development
- invested in it. This is just the first step in a long-term vision
- of making interactive and concurrent C++ programs easier to
- write. **Put your logo here and help this project's long term
- sustainability by buying a sponsorship package:** immer@sinusoid.al
-
-.. include:index/end
-
-Example
--------
-
-.. github does not support the ``literalinclude`` directive. This
- example is copy pasted from ``example/vector/intro.cpp``
-
-.. code-block:: c++
-
- #include <immer/vector.hpp>
- int main()
- {
- const auto v0 = immer::vector<int>{};
- const auto v1 = v0.push_back(13);
- assert(v0.size() == 0 && v1.size() == 1 && v1[0] == 13);
-
- const auto v2 = v1.set(0, 42);
- assert(v1[0] == 13 && v2[0] == 42);
- }
-..
-
- For a **complete example** check `Ewig, a simple didactic
- text-editor <https://github.com/arximboldi/ewig>`_ built with this
- library. You may also wanna check `Lager, a Redux-like library
- <https://github.com/arximboldi/lager>`_ for writing interactive
- software in C++ using a value-oriented design.
-
-
-Why?
-----
-
-In the last few years, there has been a growing interest in immutable
-data structures, motivated by the horizontal scaling of our processing
-power and the ubiquity of highly interactive systems. Languages like
-Clojure_ and Scala_ provide them by default, and implementations
-for JavaScript like Mori_ and Immutable.js_ are widely used,
-specially in combination with modern UI frameworks like React_.
-
-Interactivity
- Thanks to *persistence* and *structural sharing*, new values can
- be efficiently compared with old ones. This enables simpler ways of
- *reasoning about change* that sit at the core of modern
- interactive systems programming paradigms like `reactive
- programming`_.
-
-Concurrency
- Passing immutable data structures by value does not need to copy
- any data. In the absence of mutation, data can be safely read
- from multiple concurrent processes, and enable concurrency
- patterns like `share by communicating`_ efficiently.
-
-Parallelism
- Some recent immutable data structures have interesting properties
- like :math:`O(log(n))` concatenation, which enable new kinds of
- `parallelization algorithms`_.
-
-.. _clojure: http://clojure.org/reference/data_structures
-.. _scala: http://docs.scala-lang.org/overviews/collections/overview.html
-
-.. _mori: https://swannodette.github.io/mori/
-.. _immutable.js: https://github.com/facebook/immutable-js
-.. _react: https://facebook.github.io/react/
-
-.. _reactive programming: https://en.wikipedia.org/wiki/Reactive_programming
-.. _share by communicating: https://blog.golang.org/share-memory-by-communicating
-.. _parallelization algorithms: http://docs.scala-lang.org/overviews/parallel-collections/overview.html
-
-Features
---------
-
-Idiomatic
- This library doesn't pretend that it is written in Haskell. It
- leverages features from recent standards to provide an API that is
- both efficient and natural for a C++ developer.
-
-Performant
- You use C++ because you need this. *Immer* implements state of
- the art data structures with efficient cache utilization and have
- been proven production ready in other languages. It also includes
- our own improvements over that are only possible because of the
- C++'s ability to abstract over memory layout. We monitor the
- performance impact of every change by collecting `benchmark
- results`_ directly from CI.
-
-.. _benchmark results: https://public.sinusoid.es/misc/immer/reports/
-
-Customizable
- We leverage templates and `policy-based design`_ to build
- data-structures that can be adapted to work efficiently for
- various purposes and architectures, for example, by choosing among
- various `memory management strategies`. This turns
- *immer* into a good foundation to provide immutable data
- structures to higher level languages with a C runtime, like
- Python_ or Guile_.
-
-.. _python: https://www.python.org/
-.. _guile: https://www.gnu.org/software/guile/
-.. _policy-based design: https://en.wikipedia.org/wiki/Policy-based_design
-.. _memory management strategies: https://sinusoid.es/immer/memory.html
-
-Dependencies
-------------
-
-This library is written in **C++14** and a compliant compiler is
-necessary. It is `continuously tested`_ with Clang 3.8 and GCC 6, but
-it might work with other compilers and versions.
-
-No external library is necessary and there are no other requirements.
-
-.. _continuously tested: https://travis-ci.org/arximboldi/immer
-
-Usage
------
-
-This is a **header only** library. You can just copy the ``immer``
-subfolder somewhere in your *include path*.
-
-If you are using the `Nix package manager`_ (we strongly recommend it)
-you can just::
-
- nix-env -if https://github.com/arximboldi/immer/archive/master.tar.gz
-
-Alternatively, you can use `CMake`_ to install the library in your
-system once you have manually cloned the repository::
-
- mkdir -p build && cd build
- cmake .. && sudo make install
-
-.. _nix package manager: https://nixos.org/nix
-.. _cmake: https://cmake.org/
-
-Development
------------
-
-In order to develop the library, you will need to compile and run the
-examples, tests and benchmarks. These require some additional tools.
-The easiest way to install them is by using the `Nix package
-manager`_. At the root of the repository just type::
-
- nix-shell
-
-This will download all required dependencies and create an isolated
-environment in which you can use these dependencies, without polluting
-your system.
-
-Then you can proceed to generate a development project using `CMake`_::
-
- mkdir build && cd build
- cmake ..
-
-From then on, one may build and run all tests by doing::
-
- make check
-
-In order to build and run all benchmarks when running ``make check``,
-run ``cmake`` again with the option ``-DCHECK_BENCHMARKS=1``. The
-results of running the benchmarks will be saved to a folder
-``reports/`` in the project root.
-
-License
--------
-
-**This software is licensed under the Boost Software License 1.0**.
-
-.. image:: https://upload.wikimedia.org/wikipedia/commons/c/cd/Boost.png
- :alt: Boost logo
- :target: http://boost.org/LICENSE_1_0.txt
- :align: right
-
-The full text of the license is can be accessed `via this link
-<http://boost.org/LICENSE_1_0.txt>`_ and is also included
-in the ``LICENSE`` file of this software package.
diff --git a/src/third_party/immer/dist/immer/algorithm.hpp b/src/third_party/immer/dist/immer/algorithm.hpp
deleted file mode 100644
index 382df02dbce..00000000000
--- a/src/third_party/immer/dist/immer/algorithm.hpp
+++ /dev/null
@@ -1,325 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <algorithm>
-#include <cassert>
-#include <functional>
-#include <numeric>
-#include <type_traits>
-
-namespace immer {
-
-/**
- * @defgroup algorithm
- * @{
- */
-
-/*@{*/
-// Right now these algorithms dispatch directly to the vector
-// implementations unconditionally. This will be changed in the
-// future to support other kinds of containers.
-
-/*!
- * Apply operation `fn` for every contiguous *chunk* of data in the
- * range sequentially. Each time, `Fn` is passed two `value_type`
- * pointers describing a range over a part of the vector. This allows
- * iterating over the elements in the most efficient way.
- *
- * @rst
- *
- * .. tip:: This is a low level method. Most of the time, :doc:`other
- * wrapper algorithms <algorithms>` should be used instead.
- *
- * @endrst
- */
-template <typename Range, typename Fn>
-void for_each_chunk(const Range& r, Fn&& fn)
-{
- r.impl().for_each_chunk(std::forward<Fn>(fn));
-}
-
-template <typename Iterator, typename Fn>
-void for_each_chunk(const Iterator& first, const Iterator& last, Fn&& fn)
-{
- assert(&first.impl() == &last.impl());
- first.impl().for_each_chunk(
- first.index(), last.index(), std::forward<Fn>(fn));
-}
-
-template <typename T, typename Fn>
-void for_each_chunk(const T* first, const T* last, Fn&& fn)
-{
- std::forward<Fn>(fn)(first, last);
-}
-
-/*!
- * Apply operation `fn` for every contiguous *chunk* of data in the
- * range sequentially, until `fn` returns `false`. Each time, `Fn` is
- * passed two `value_type` pointers describing a range over a part of
- * the vector. This allows iterating over the elements in the most
- * efficient way.
- *
- * @rst
- *
- * .. tip:: This is a low level method. Most of the time, :doc:`other
- * wrapper algorithms <algorithms>` should be used instead.
- *
- * @endrst
- */
-template <typename Range, typename Fn>
-bool for_each_chunk_p(const Range& r, Fn&& fn)
-{
- return r.impl().for_each_chunk_p(std::forward<Fn>(fn));
-}
-
-template <typename Iterator, typename Fn>
-bool for_each_chunk_p(const Iterator& first, const Iterator& last, Fn&& fn)
-{
- assert(&first.impl() == &last.impl());
- return first.impl().for_each_chunk_p(
- first.index(), last.index(), std::forward<Fn>(fn));
-}
-
-template <typename T, typename Fn>
-bool for_each_chunk_p(const T* first, const T* last, Fn&& fn)
-{
- return std::forward<Fn>(fn)(first, last);
-}
-
-namespace detail {
-
-template <class Iter, class T>
-T accumulate_move(Iter first, Iter last, T init)
-{
- for (; first != last; ++first)
- init = std::move(init) + *first;
- return init;
-}
-
-template <class Iter, class T, class Fn>
-T accumulate_move(Iter first, Iter last, T init, Fn op)
-{
- for (; first != last; ++first)
- init = op(std::move(init), *first);
- return init;
-}
-
-} // namespace detail
-
-/*!
- * Equivalent of `std::accumulate` applied to the range `r`.
- */
-template <typename Range, typename T>
-T accumulate(Range&& r, T init)
-{
- for_each_chunk(r, [&](auto first, auto last) {
- init = detail::accumulate_move(first, last, init);
- });
- return init;
-}
-
-template <typename Range, typename T, typename Fn>
-T accumulate(Range&& r, T init, Fn fn)
-{
- for_each_chunk(r, [&](auto first, auto last) {
- init = detail::accumulate_move(first, last, init, fn);
- });
- return init;
-}
-
-/*!
- * Equivalent of `std::accumulate` applied to the range @f$ [first,
- * last) @f$.
- */
-template <typename Iterator, typename T>
-T accumulate(Iterator first, Iterator last, T init)
-{
- for_each_chunk(first, last, [&](auto first, auto last) {
- init = detail::accumulate_move(first, last, init);
- });
- return init;
-}
-
-template <typename Iterator, typename T, typename Fn>
-T accumulate(Iterator first, Iterator last, T init, Fn fn)
-{
- for_each_chunk(first, last, [&](auto first, auto last) {
- init = detail::accumulate_move(first, last, init, fn);
- });
- return init;
-}
-
-/*!
- * Equivalent of `std::for_each` applied to the range `r`.
- */
-template <typename Range, typename Fn>
-Fn&& for_each(Range&& r, Fn&& fn)
-{
- for_each_chunk(r, [&](auto first, auto last) {
- for (; first != last; ++first)
- fn(*first);
- });
- return std::forward<Fn>(fn);
-}
-
-/*!
- * Equivalent of `std::for_each` applied to the range @f$ [first,
- * last) @f$.
- */
-template <typename Iterator, typename Fn>
-Fn&& for_each(Iterator first, Iterator last, Fn&& fn)
-{
- for_each_chunk(first, last, [&](auto first, auto last) {
- for (; first != last; ++first)
- fn(*first);
- });
- return std::forward<Fn>(fn);
-}
-
-/*!
- * Equivalent of `std::copy` applied to the range `r`.
- */
-template <typename Range, typename OutIter>
-OutIter copy(Range&& r, OutIter out)
-{
- for_each_chunk(
- r, [&](auto first, auto last) { out = std::copy(first, last, out); });
- return out;
-}
-
-/*!
- * Equivalent of `std::copy` applied to the range @f$ [first,
- * last) @f$.
- */
-template <typename InIter, typename OutIter>
-OutIter copy(InIter first, InIter last, OutIter out)
-{
- for_each_chunk(first, last, [&](auto first, auto last) {
- out = std::copy(first, last, out);
- });
- return out;
-}
-
-/*!
- * Equivalent of `std::all_of` applied to the range `r`.
- */
-template <typename Range, typename Pred>
-bool all_of(Range&& r, Pred p)
-{
- return for_each_chunk_p(
- r, [&](auto first, auto last) { return std::all_of(first, last, p); });
-}
-
-/*!
- * Equivalent of `std::all_of` applied to the range @f$ [first, last)
- * @f$.
- */
-template <typename Iter, typename Pred>
-bool all_of(Iter first, Iter last, Pred p)
-{
- return for_each_chunk_p(first, last, [&](auto first, auto last) {
- return std::all_of(first, last, p);
- });
-}
-
-/*!
- * Object that can be used to process changes as computed by the @a diff
- * algorithm.
- *
- * @tparam AddedFn Unary function that is be called whenever an added element is
- * found. It is called with the added element as argument.
- *
- * @tparam RemovedFn Unary function that is called whenever a removed element is
- * found. It is called with the removed element as argument.
- *
- * @tparam ChangedFn Unary function that is called whenever a changed element is
- * found. It is called with the changed element as argument.
- */
-template <class AddedFn, class RemovedFn, class ChangedFn>
-struct differ
-{
- AddedFn added;
- RemovedFn removed;
- ChangedFn changed;
-};
-
-/*!
- * Produces a @a differ object with `added`, `removed` and `changed` functions.
- */
-template <class AddedFn, class RemovedFn, class ChangedFn>
-auto make_differ(AddedFn&& added, RemovedFn&& removed, ChangedFn&& changed)
- -> differ<std::decay_t<AddedFn>,
- std::decay_t<RemovedFn>,
- std::decay_t<ChangedFn>>
-{
- return {std::forward<AddedFn>(added),
- std::forward<RemovedFn>(removed),
- std::forward<ChangedFn>(changed)};
-}
-
-/*!
- * Produces a @a differ object with `added` and `removed` functions and no
- * `changed` function.
- */
-template <class AddedFn, class RemovedFn>
-auto make_differ(AddedFn&& added, RemovedFn&& removed)
-{
- return make_differ(std::forward<AddedFn>(added),
- std::forward<RemovedFn>(removed),
- [](auto&&...) {});
-}
-
-/*!
- * Compute the differences between `a` and `b`.
- *
- * Changes detected are notified via the differ object, which should support the
- * following expressions:
- *
- * - `differ.added(x)`, invoked when element `x` is found in `b` but not in
- * `a`.
- *
- * - `differ.removed(x)`, invoked when element `x` is found in `a` but not in
- * `b`.
- *
- * - `differ.changed(x, y)`, invoked when element `x` and `y` from `a` and `b`
- * share the same key but map to a different value.
- *
- * This method leverages structural sharing to offer a complexity @f$ O(|diff|)
- * @f$ when `b` is derived from `a` by performing @f$ |diff| @f$ updates. This
- * is, this function can detect changes in effectively constant time per update,
- * as oposed to the @f$ O(|a|+|b|) @f$ complexity of a trivial implementation.
- *
- * @rst
- *
- * .. note:: This method is only implemented for ``map`` and ``set``. When sets
- * are diffed, the ``changed`` function is never called.
- *
- * @endrst
- */
-template <typename T, typename Differ>
-void diff(const T& a, const T& b, Differ&& differ)
-{
- a.impl().template diff<std::equal_to<typename T::value_type>>(
- b.impl(), std::forward<Differ>(differ));
-}
-
-/*!
- * Compute the differences between `a` and `b` using the callbacks in `fns` as
- * differ. Equivalent to `diff(a, b, make_differ(fns)...)`.
- */
-template <typename T, typename... Fns>
-void diff(const T& a, const T& b, Fns&&... fns)
-{
- diff(a, b, make_differ(std::forward<Fns>(fns)...));
-}
-
-/** @} */ // group: algorithm
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/array.hpp b/src/third_party/immer/dist/immer/array.hpp
deleted file mode 100644
index f71477c2395..00000000000
--- a/src/third_party/immer/dist/immer/array.hpp
+++ /dev/null
@@ -1,375 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/arrays/with_capacity.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <cstddef>
-
-namespace immer {
-
-template <typename T, typename MemoryPolicy>
-class array_transient;
-
-/*!
- * Immutable container that stores a sequence of elements in
- * contiguous memory.
- *
- * @tparam T The type of the values to be stored in the container.
- *
- * @rst
- *
- * It supports the most efficient iteration and random access,
- * equivalent to a ``std::vector`` or ``std::array``, but all
- * manipulations are :math:`O(size)`.
- *
- * .. tip:: Don't be fooled by the bad complexity of this data
- * structure. It is a great choice for short sequence or when it
- * is seldom or never changed. This depends on the ``sizeof(T)``
- * and the expensiveness of its ``T``'s copy constructor. In case
- * of doubt, measure. For basic types, using an `array` when
- * :math:`n < 100` is a good heuristic.
- *
- * @endrst
- */
-template <typename T, typename MemoryPolicy = default_memory_policy>
-class array
-{
- using impl_t =
- std::conditional_t<MemoryPolicy::use_transient_rvalues,
- detail::arrays::with_capacity<T, MemoryPolicy>,
- detail::arrays::no_capacity<T, MemoryPolicy>>;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
-public:
- using value_type = T;
- using reference = const T&;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = const T*;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using memory_policy = MemoryPolicy;
- using transient_type = array_transient<T, MemoryPolicy>;
-
- /*!
- * Default constructor. It creates an array of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- array() = default;
-
- /*!
- * Constructs an array containing the elements in `values`.
- */
- array(std::initializer_list<T> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a array containing the elements in the range
- * defined by the forward iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent> &&
- detail::is_forward_iterator_v<Iter>,
- bool> = true>
- array(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Constructs an array containing the element `val` repeated `n`
- * times.
- */
- array(size_type n, T v = {})
- : impl_{impl_t::from_fill(n, v)}
- {}
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return impl_.data(); }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate memory and its complexity is @f$ O(1)
- * @f$.
- */
- IMMER_NODISCARD iterator end() const { return impl_.data() + impl_.size; }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD std::size_t size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Access the raw data.
- */
- IMMER_NODISCARD const T* data() const { return impl_.data(); }
-
- /*!
- * Access the last element.
- */
- IMMER_NODISCARD const T& back() const { return data()[size() - 1]; }
-
- /*!
- * Access the first element.
- */
- IMMER_NODISCARD const T& front() const { return data()[0]; }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- IMMER_NODISCARD reference operator[](size_type index) const
- {
- return impl_.get(index);
- }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Returns whether the vectors are equal.
- */
- IMMER_NODISCARD bool operator==(const array& other) const
- {
- return impl_.equals(other.impl_);
- }
- IMMER_NODISCARD bool operator!=(const array& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns an array with `value` inserted at the end. It may
- * allocate memory and its complexity is @f$ O(size) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/array/array.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: push-back/start
- * :end-before: push-back/end
- *
- * @endrst
- */
- IMMER_NODISCARD array push_back(value_type value) const&
- {
- return impl_.push_back(std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) push_back(value_type value) &&
- {
- return push_back_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns an array containing value `value` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is @f$ O(size) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/array/array.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: set/start
- * :end-before: set/end
- *
- * @endrst
- */
- IMMER_NODISCARD array set(std::size_t index, value_type value) const&
- {
- return impl_.assoc(index, std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) set(size_type index, value_type value) &&
- {
- return set_move(move_t{}, index, std::move(value));
- }
-
- /*!
- * Returns an array containing the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is @f$ O(size) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/array/array.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: update/start
- * :end-before: update/end
- *
- * @endrst
- */
- template <typename FnT>
- IMMER_NODISCARD array update(std::size_t index, FnT&& fn) const&
- {
- return impl_.update(index, std::forward<FnT>(fn));
- }
-
- template <typename FnT>
- IMMER_NODISCARD decltype(auto) update(size_type index, FnT&& fn) &&
- {
- return update_move(move_t{}, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Returns a array containing only the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/array/array.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: take/start
- * :end-before: take/end
- *
- * @endrst
- */
- IMMER_NODISCARD array take(size_type elems) const&
- {
- return impl_.take(elems);
- }
-
- IMMER_NODISCARD decltype(auto) take(size_type elems) &&
- {
- return take_move(move_t{}, elems);
- }
-
- /*!
- * Returns an @a transient form of this container, an
- * `immer::array_transient`.
- */
- IMMER_NODISCARD transient_type transient() const&
- {
- return transient_type{impl_};
- }
- IMMER_NODISCARD transient_type transient() &&
- {
- return transient_type{std::move(impl_)};
- }
-
- /*!
- * Returns a value that can be used as identity for the container. If two
- * values have the same identity, they are guaranteed to be equal and to
- * contain the same objects. However, two equal containers are not
- * guaranteed to have the same identity.
- */
- void* identity() const { return impl_.ptr; }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-private:
- friend transient_type;
-
- array(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- array&& push_back_move(std::true_type, value_type value)
- {
- impl_.push_back_mut({}, std::move(value));
- return std::move(*this);
- }
- array push_back_move(std::false_type, value_type value)
- {
- return impl_.push_back(std::move(value));
- }
-
- array&& set_move(std::true_type, size_type index, value_type value)
- {
- impl_.assoc_mut({}, index, std::move(value));
- return std::move(*this);
- }
- array set_move(std::false_type, size_type index, value_type value)
- {
- return impl_.assoc(index, std::move(value));
- }
-
- template <typename Fn>
- array&& update_move(std::true_type, size_type index, Fn&& fn)
- {
- impl_.update_mut({}, index, std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- array update_move(std::false_type, size_type index, Fn&& fn)
- {
- return impl_.update(index, std::forward<Fn>(fn));
- }
-
- array&& take_move(std::true_type, size_type elems)
- {
- impl_.take_mut({}, elems);
- return std::move(*this);
- }
- array take_move(std::false_type, size_type elems)
- {
- return impl_.take(elems);
- }
-
- impl_t impl_ = impl_t::empty();
-};
-
-} /* namespace immer */
diff --git a/src/third_party/immer/dist/immer/array_transient.hpp b/src/third_party/immer/dist/immer/array_transient.hpp
deleted file mode 100644
index 08000b2d92b..00000000000
--- a/src/third_party/immer/dist/immer/array_transient.hpp
+++ /dev/null
@@ -1,204 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/arrays/with_capacity.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <cstddef>
-
-namespace immer {
-
-template <typename T, typename MemoryPolicy>
-class array;
-
-/*!
- * Mutable version of `immer::array`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename T, typename MemoryPolicy = default_memory_policy>
-class array_transient : MemoryPolicy::transience_t::owner
-{
- using impl_t = detail::arrays::with_capacity<T, MemoryPolicy>;
- using impl_no_capacity_t = detail::arrays::no_capacity<T, MemoryPolicy>;
- using owner_t = typename MemoryPolicy::transience_t::owner;
-
-public:
- using value_type = T;
- using reference = const T&;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = const T*;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using memory_policy = MemoryPolicy;
- using persistent_type = array<T, MemoryPolicy>;
-
- /*!
- * Default constructor. It creates a mutable array of `size() ==
- * 0`. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- array_transient() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return impl_.data(); }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const { return impl_.data() + impl_.size; }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD std::size_t size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Access the raw data.
- */
- IMMER_NODISCARD const T* data() const { return impl_.data(); }
-
- /*!
- * Provide mutable access to the raw underlaying data.
- */
- IMMER_NODISCARD T* data_mut() { return impl_.data_mut(*this); }
-
- /*!
- * Access the last element.
- */
- IMMER_NODISCARD const T& back() const { return data()[size() - 1]; }
-
- /*!
- * Access the first element.
- */
- IMMER_NODISCARD const T& front() const { return data()[0]; }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ 0 index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- reference operator[](size_type index) const { return impl_.get(index); }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Inserts `value` at the end. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- void push_back(value_type value)
- {
- impl_.push_back_mut(*this, std::move(value));
- }
-
- /*!
- * Sets to the value `value` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void set(size_type index, value_type value)
- {
- impl_.assoc_mut(*this, index, std::move(value));
- }
-
- /*!
- * Updates the array to contain the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `0 >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- template <typename FnT>
- void update(size_type index, FnT&& fn)
- {
- impl_.update_mut(*this, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Resizes the array to only contain the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void take(size_type elems) { impl_.take_mut(*this, elems); }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::array`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return persistent_type{impl_};
- }
- IMMER_NODISCARD persistent_type persistent() &&
- {
- return persistent_type{std::move(impl_)};
- }
-
-private:
- friend persistent_type;
-
- array_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/atom.hpp b/src/third_party/immer/dist/immer/atom.hpp
deleted file mode 100644
index 2cf409b916b..00000000000
--- a/src/third_party/immer/dist/immer/atom.hpp
+++ /dev/null
@@ -1,254 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/box.hpp>
-#include <immer/refcount/no_refcount_policy.hpp>
-
-#include <atomic>
-#include <type_traits>
-
-namespace immer {
-
-namespace detail {
-
-template <typename T, typename MemoryPolicy>
-struct refcount_atom_impl
-{
- using box_type = box<T, MemoryPolicy>;
- using value_type = T;
- using memory_policy = MemoryPolicy;
- using lock_t = typename MemoryPolicy::lock;
- using scoped_lock_t = typename lock_t::scoped_lock;
-
- refcount_atom_impl(const refcount_atom_impl&) = delete;
- refcount_atom_impl(refcount_atom_impl&&) = delete;
- refcount_atom_impl& operator=(const refcount_atom_impl&) = delete;
- refcount_atom_impl& operator=(refcount_atom_impl&&) = delete;
-
- refcount_atom_impl(box_type b)
- : impl_{std::move(b)}
- {}
-
- box_type load() const
- {
- scoped_lock_t lock{lock_};
- return impl_;
- }
-
- void store(box_type b)
- {
- scoped_lock_t lock{lock_};
- impl_ = std::move(b);
- }
-
- box_type exchange(box_type b)
- {
- {
- scoped_lock_t lock{lock_};
- swap(b, impl_);
- }
- return b;
- }
-
- template <typename Fn>
- box_type update(Fn&& fn)
- {
- while (true) {
- auto oldv = load();
- auto newv = oldv.update(fn);
- {
- scoped_lock_t lock{lock_};
- if (oldv.impl_ == impl_.impl_) {
- impl_ = newv;
- return {newv};
- }
- }
- }
- }
-
-private:
- mutable lock_t lock_;
- box_type impl_;
-};
-
-template <typename T, typename MemoryPolicy>
-struct gc_atom_impl
-{
- using box_type = box<T, MemoryPolicy>;
- using value_type = T;
- using memory_policy = MemoryPolicy;
-
- static_assert(std::is_same<typename MemoryPolicy::refcount,
- no_refcount_policy>::value,
- "gc_atom_impl can only be used when there is no refcount!");
-
- gc_atom_impl(const gc_atom_impl&) = delete;
- gc_atom_impl(gc_atom_impl&&) = delete;
- gc_atom_impl& operator=(const gc_atom_impl&) = delete;
- gc_atom_impl& operator=(gc_atom_impl&&) = delete;
-
- gc_atom_impl(box_type b)
- : impl_{b.impl_}
- {}
-
- box_type load() const { return {impl_.load()}; }
-
- void store(box_type b) { impl_.store(b.impl_); }
-
- box_type exchange(box_type b) { return {impl_.exchange(b.impl_)}; }
-
- template <typename Fn>
- box_type update(Fn&& fn)
- {
- while (true) {
- auto oldv = box_type{impl_.load()};
- auto newv = oldv.update(fn);
- if (impl_.compare_exchange_weak(oldv.impl_, newv.impl_))
- return {newv};
- }
- }
-
-private:
- std::atomic<typename box_type::holder*> impl_;
-};
-
-} // namespace detail
-
-/*!
- * Stores for boxed values of type `T` in a thread-safe manner.
- *
- * @see box
- *
- * @rst
- *
- * .. warning:: If memory policy used includes thread unsafe reference counting,
- * no thread safety is assumed, and the atom becomes thread unsafe too!
- *
- * .. note:: ``box<T>`` provides a value based box of type ``T``, this is, we
- * can think about it as a value-based version of ``std::shared_ptr``. In a
- * similar fashion, ``atom<T>`` is in spirit the value-based equivalent of
- * C++20 ``std::atomic_shared_ptr``. However, the API does not follow
- * ``std::atomic`` interface closely, since it attempts to be a higher level
- * construction, most similar to Clojure's ``(atom)``. It is remarkable in
- * particular that, since ``box<T>`` underlying object is immutable, using
- * ``atom<T>`` is fully thread-safe in ways that ``std::atomic_shared_ptr`` is
- * not. This is so because dereferencing the underlying pointer in a
- * ``std::atomic_share_ptr`` may require further synchronization, in
- * particular when invoking non-const methods.
- *
- * @endrst
- */
-template <typename T, typename MemoryPolicy = default_memory_policy>
-class atom
-{
-public:
- using box_type = box<T, MemoryPolicy>;
- using value_type = T;
- using memory_policy = MemoryPolicy;
-
- atom(const atom&) = delete;
- atom(atom&&) = delete;
- void operator=(const atom&) = delete;
- void operator=(atom&&) = delete;
-
- /*!
- * Constructs an atom holding a value `b`;
- */
- atom(box_type v = {})
- : impl_{std::move(v)}
- {}
-
- /*!
- * Sets a new value in the atom.
- */
- atom& operator=(box_type b)
- {
- impl_.store(std::move(b));
- return *this;
- }
-
- /*!
- * Reads the currently stored value in a thread-safe manner.
- */
- operator box_type() const { return impl_.load(); }
-
- /*!
- * Reads the currently stored value in a thread-safe manner.
- */
- operator value_type() const { return *impl_.load(); }
-
- /*!
- * Reads the currently stored value in a thread-safe manner.
- */
- IMMER_NODISCARD box_type load() const { return impl_.load(); }
-
- /*!
- * Stores a new value in a thread-safe manner.
- */
- void store(box_type b) { impl_.store(std::move(b)); }
-
- /*!
- * Stores a new value and returns the old value, in a thread-safe manner.
- */
- IMMER_NODISCARD box_type exchange(box_type b)
- {
- return impl_.exchange(std::move(b));
- }
-
- /*!
- * Stores the result of applying `fn` to the current value atomically and
- * returns the new resulting value.
- *
- * @rst
- *
- * .. warning:: ``fn`` must be a pure function and have no side effects! The
- * function might be evaluated multiple times when multiple threads
- * content to update the value.
- *
- * @endrst
- */
- template <typename Fn>
- box_type update(Fn&& fn)
- {
- return impl_.update(std::forward<Fn>(fn));
- }
-
-private:
- struct get_refcount_atom_impl
- {
- template <typename U, typename MP>
- struct apply
- {
- using type = detail::refcount_atom_impl<U, MP>;
- };
- };
-
- struct get_gc_atom_impl
- {
- template <typename U, typename MP>
- struct apply
- {
- using type = detail::gc_atom_impl<U, MP>;
- };
- };
-
- // If we are using "real" garbage collection (we assume this when we use
- // `no_refcount_policy`), we just store the pointer in an atomic. If we use
- // reference counting, we rely on the reference counting spinlock.
- using impl_t = typename std::conditional_t<
- std::is_same<typename MemoryPolicy::refcount,
- no_refcount_policy>::value,
- get_gc_atom_impl,
- get_refcount_atom_impl>::template apply<T, MemoryPolicy>::type;
-
- impl_t impl_;
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/box.hpp b/src/third_party/immer/dist/immer/box.hpp
deleted file mode 100644
index 711ac78f099..00000000000
--- a/src/third_party/immer/dist/immer/box.hpp
+++ /dev/null
@@ -1,240 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/util.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <cstddef>
-
-namespace immer {
-
-namespace detail {
-
-template <typename U, typename MP>
-struct gc_atom_impl;
-
-template <typename U, typename MP>
-struct refcount_atom_impl;
-
-} // namespace detail
-
-/*!
- * Immutable box for a single value of type `T`.
- *
- * The box is always copiable and movable. The `T` copy or move
- * operations are never called. Since a box is immutable, copying or
- * moving just copy the underlying pointers.
- */
-template <typename T, typename MemoryPolicy = default_memory_policy>
-class box
-{
- friend struct detail::gc_atom_impl<T, MemoryPolicy>;
- friend struct detail::refcount_atom_impl<T, MemoryPolicy>;
-
- struct holder : MemoryPolicy::refcount
- {
- T value;
-
- template <typename... Args>
- holder(Args&&... args)
- : value{std::forward<Args>(args)...}
- {}
- };
-
- using heap = typename MemoryPolicy::heap::type;
-
- holder* impl_ = nullptr;
-
- box(holder* impl)
- : impl_{impl}
- {}
-
-public:
- const holder* impl() const { return impl_; };
-
- using value_type = T;
- using memory_policy = MemoryPolicy;
-
- /*!
- * Constructs a box holding `T{}`.
- */
- box()
- : impl_{detail::make<heap, holder>()}
- {}
-
- /*!
- * Constructs a box holding `T{arg}`
- */
- template <typename Arg,
- typename Enable = std::enable_if_t<
- !std::is_same<box, std::decay_t<Arg>>::value &&
- std::is_constructible<T, Arg>::value>>
- box(Arg&& arg)
- : impl_{detail::make<heap, holder>(std::forward<Arg>(arg))}
- {}
-
- /*!
- * Constructs a box holding `T{arg1, arg2, args...}`
- */
- template <typename Arg1, typename Arg2, typename... Args>
- box(Arg1&& arg1, Arg2&& arg2, Args&&... args)
- : impl_{detail::make<heap, holder>(std::forward<Arg1>(arg1),
- std::forward<Arg2>(arg2),
- std::forward<Args>(args)...)}
- {}
-
- friend void swap(box& a, box& b)
- {
- using std::swap;
- swap(a.impl_, b.impl_);
- }
-
- box(box&& other) { swap(*this, other); }
- box(const box& other)
- : impl_(other.impl_)
- {
- impl_->inc();
- }
- box& operator=(box&& other)
- {
- swap(*this, other);
- return *this;
- }
- box& operator=(const box& other)
- {
- auto aux = other;
- swap(*this, aux);
- return *this;
- }
- ~box()
- {
- if (impl_ && impl_->dec()) {
- impl_->~holder();
- heap::deallocate(sizeof(holder), impl_);
- }
- }
-
- /*! Query the current value. */
- IMMER_NODISCARD const T& get() const { return impl_->value; }
-
- /*! Conversion to the boxed type. */
- operator const T&() const { return get(); }
-
- /*! Access via dereference */
- const T& operator*() const { return get(); }
-
- /*! Access via pointer member access */
- const T* operator->() const { return &get(); }
-
- /*!
- * Returns a new box built by applying the `fn` to the underlying
- * value.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/box/box.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: update/start
- * :end-before: update/end
- *
- * @endrst
- */
- template <typename Fn>
- IMMER_NODISCARD box update(Fn&& fn) const&
- {
- return std::forward<Fn>(fn)(get());
- }
- template <typename Fn>
- IMMER_NODISCARD box&& update(Fn&& fn) &&
- {
- if (impl_->unique())
- impl_->value = std::forward<Fn>(fn)(std::move(impl_->value));
- else
- *this = std::forward<Fn>(fn)(impl_->value);
- return std::move(*this);
- }
-};
-
-template <typename T, typename MP>
-IMMER_NODISCARD bool operator==(const box<T, MP>& a, const box<T, MP>& b)
-{
- return a.impl() == b.impl() || a.get() == b.get();
-}
-template <typename T, typename MP>
-IMMER_NODISCARD bool operator!=(const box<T, MP>& a, const box<T, MP>& b)
-{
- return a.impl() != b.impl() && a.get() != b.get();
-}
-template <typename T, typename MP>
-IMMER_NODISCARD bool operator<(const box<T, MP>& a, const box<T, MP>& b)
-{
- return a.impl() != b.impl() && a.get() < b.get();
-}
-
-template <typename T, typename MP, typename T2>
-IMMER_NODISCARD auto operator==(const box<T, MP>& a, T2&& b)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(a.get() == b)>
-{
- return a.get() == b;
-}
-template <typename T, typename MP, typename T2>
-IMMER_NODISCARD auto operator!=(const box<T, MP>& a, T2&& b)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(a.get() != b)>
-{
- return a.get() != b;
-}
-template <typename T, typename MP, typename T2>
-IMMER_NODISCARD auto operator<(const box<T, MP>& a, T2&& b)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(a.get() < b)>
-{
- return a.get() < b;
-}
-
-template <typename T2, typename T, typename MP>
-IMMER_NODISCARD auto operator==(T2&& b, const box<T, MP>& a)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(a.get() == b)>
-{
- return a.get() == b;
-}
-template <typename T2, typename T, typename MP>
-IMMER_NODISCARD auto operator!=(T2&& b, const box<T, MP>& a)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(a.get() != b)>
-{
- return a.get() != b;
-}
-template <typename T2, typename T, typename MP>
-IMMER_NODISCARD auto operator<(T2&& b, const box<T, MP>& a)
- -> std::enable_if_t<!std::is_same<box<T, MP>, std::decay_t<T2>>::value,
- decltype(b < a.get())>
-{
- return b < a.get();
-}
-
-} // namespace immer
-
-namespace std {
-
-template <typename T, typename MP>
-struct hash<immer::box<T, MP>>
-{
- std::size_t operator()(const immer::box<T, MP>& x) const
- {
- return std::hash<T>{}(*x);
- }
-};
-
-} // namespace std
diff --git a/src/third_party/immer/dist/immer/config.hpp b/src/third_party/immer/dist/immer/config.hpp
deleted file mode 100644
index 20833c303a6..00000000000
--- a/src/third_party/immer/dist/immer/config.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
-#define IMMER_HAS_CPP17 1
-#endif
-
-#if defined(__has_cpp_attribute)
-#if __has_cpp_attribute(nodiscard)
-#define IMMER_NODISCARD [[nodiscard]]
-#endif
-#else
-#if _MSVC_LANG >= 201703L
-#define IMMER_NODISCARD [[nodiscard]]
-#endif
-#endif
-
-#if 0 // MongoDB: Disable clang-specific feature check. Never disable exceptions.
-#ifdef __has_feature
-#if !__has_feature(cxx_exceptions)
-#define IMMER_NO_EXCEPTIONS
-#endif
-#endif
-#endif // 0
-
-#ifdef IMMER_NO_EXCEPTIONS
-#define IMMER_TRY if (true)
-#define IMMER_CATCH(expr) else
-#define IMMER_THROW(expr) \
- do { \
- assert(!#expr); \
- std::terminate(); \
- } while (false)
-#define IMMER_RETHROW
-#else
-#define IMMER_TRY try
-#define IMMER_CATCH(expr) catch (expr)
-#define IMMER_THROW(expr) throw expr
-#define IMMER_RETHROW throw
-#endif
-
-#ifndef IMMER_NODISCARD
-#define IMMER_NODISCARD
-#endif
-
-#ifndef IMMER_TAGGED_NODE
-#ifdef NDEBUG
-#define IMMER_TAGGED_NODE 0
-#else
-#define IMMER_TAGGED_NODE 1
-#endif
-#endif
-
-#if IMMER_TAGGED_NODE
-#define IMMER_ASSERT_TAGGED(assertion) assert(assertion)
-#else
-#define IMMER_ASSERT_TAGGED(assertion)
-#endif
-
-#ifndef IMMER_DEBUG_TRACES
-#define IMMER_DEBUG_TRACES 0
-#endif
-
-#ifndef IMMER_DEBUG_PRINT
-#define IMMER_DEBUG_PRINT 0
-#endif
-
-#ifndef IMMER_DEBUG_STATS
-#define IMMER_DEBUG_STATS 0
-#endif
-
-#ifndef IMMER_DEBUG_DEEP_CHECK
-#define IMMER_DEBUG_DEEP_CHECK 0
-#endif
-
-#if IMMER_DEBUG_TRACES || IMMER_DEBUG_PRINT
-#include <iostream>
-#include <prettyprint.hpp>
-#endif
-
-#if IMMER_DEBUG_STATS
-#include <iostream>
-#endif
-
-#if IMMER_DEBUG_TRACES
-#define IMMER_TRACE(...) std::cout << __VA_ARGS__ << std::endl
-#else
-#define IMMER_TRACE(...)
-#endif
-#define IMMER_TRACE_F(...) \
- IMMER_TRACE(__FILE__ << ":" << __LINE__ << ": " << __VA_ARGS__)
-#define IMMER_TRACE_E(expr) IMMER_TRACE(" " << #expr << " = " << (expr))
-
-#if defined(_MSC_VER)
-#define IMMER_UNREACHABLE __assume(false)
-#define IMMER_LIKELY(cond) cond
-#define IMMER_UNLIKELY(cond) cond
-#define IMMER_FORCEINLINE __forceinline
-#define IMMER_PREFETCH(p)
-#else
-#define IMMER_UNREACHABLE __builtin_unreachable()
-#define IMMER_LIKELY(cond) __builtin_expect(!!(cond), 1)
-#define IMMER_UNLIKELY(cond) __builtin_expect(!!(cond), 0)
-#define IMMER_FORCEINLINE inline __attribute__((always_inline))
-#define IMMER_PREFETCH(p)
-// #define IMMER_PREFETCH(p) __builtin_prefetch(p)
-#endif
-
-#define IMMER_DESCENT_DEEP 0
-
-#ifndef IMMER_ENABLE_DEBUG_SIZE_HEAP
-#ifdef NDEBUG
-#define IMMER_ENABLE_DEBUG_SIZE_HEAP 0
-#else
-#define IMMER_ENABLE_DEBUG_SIZE_HEAP 1
-#endif
-#endif
-
-namespace immer {
-
-const auto default_bits = 5;
-const auto default_free_list_size = 1 << 10;
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/arrays/no_capacity.hpp b/src/third_party/immer/dist/immer/detail/arrays/no_capacity.hpp
deleted file mode 100644
index a24f6da249d..00000000000
--- a/src/third_party/immer/dist/immer/detail/arrays/no_capacity.hpp
+++ /dev/null
@@ -1,211 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/algorithm.hpp>
-#include <immer/config.hpp>
-#include <immer/detail/arrays/node.hpp>
-
-#include <cassert>
-#include <cstddef>
-#include <stdexcept>
-
-namespace immer {
-namespace detail {
-namespace arrays {
-
-template <typename T, typename MemoryPolicy>
-struct no_capacity
-{
- using node_t = node<T, MemoryPolicy>;
- using edit_t = typename MemoryPolicy::transience_t::edit;
- using size_t = std::size_t;
-
- node_t* ptr;
- size_t size;
-
- static const no_capacity& empty()
- {
- static const no_capacity empty_{
- node_t::make_n(0),
- 0,
- };
- return empty_;
- }
-
- no_capacity(node_t* p, size_t s)
- : ptr{p}
- , size{s}
- {}
-
- no_capacity(const no_capacity& other)
- : no_capacity{other.ptr, other.size}
- {
- inc();
- }
-
- no_capacity(no_capacity&& other)
- : no_capacity{empty()}
- {
- swap(*this, other);
- }
-
- no_capacity& operator=(const no_capacity& other)
- {
- auto next = other;
- swap(*this, next);
- return *this;
- }
-
- no_capacity& operator=(no_capacity&& other)
- {
- swap(*this, other);
- return *this;
- }
-
- friend void swap(no_capacity& x, no_capacity& y)
- {
- using std::swap;
- swap(x.ptr, y.ptr);
- swap(x.size, y.size);
- }
-
- ~no_capacity() { dec(); }
-
- void inc()
- {
- using immer::detail::get;
- ptr->refs().inc();
- }
-
- void dec()
- {
- using immer::detail::get;
- if (ptr->refs().dec())
- node_t::delete_n(ptr, size, size);
- }
-
- T* data() { return ptr->data(); }
- const T* data() const { return ptr->data(); }
-
- T* data_mut(edit_t e)
- {
- if (!ptr->can_mutate(e))
- ptr = node_t::copy_e(e, size, ptr, size);
- return data();
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<is_forward_iterator_v<Iter> &&
- compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- static no_capacity from_range(Iter first, Sent last)
- {
- auto count = static_cast<size_t>(distance(first, last));
- if (count == 0)
- return empty();
- else
- return {
- node_t::copy_n(count, first, last),
- count,
- };
- }
-
- static no_capacity from_fill(size_t n, T v)
- {
- return {node_t::fill_n(n, v), n};
- }
-
- template <typename U>
- static no_capacity from_initializer_list(std::initializer_list<U> values)
- {
- using namespace std;
- return from_range(begin(values), end(values));
- }
-
- template <typename Fn>
- void for_each_chunk(Fn&& fn) const
- {
- std::forward<Fn>(fn)(data(), data() + size);
- }
-
- template <typename Fn>
- bool for_each_chunk_p(Fn&& fn) const
- {
- return std::forward<Fn>(fn)(data(), data() + size);
- }
-
- const T& get(std::size_t index) const { return data()[index]; }
-
- const T& get_check(std::size_t index) const
- {
- if (index >= size)
- IMMER_THROW(std::out_of_range{"out of range"});
- return data()[index];
- }
-
- bool equals(const no_capacity& other) const
- {
- return ptr == other.ptr ||
- (size == other.size &&
- std::equal(data(), data() + size, other.data()));
- }
-
- no_capacity push_back(T value) const
- {
- auto p = node_t::copy_n(size + 1, ptr, size);
- IMMER_TRY {
- new (p->data() + size) T{std::move(value)};
- return {p, size + 1};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, size + 1);
- IMMER_RETHROW;
- }
- }
-
- no_capacity assoc(std::size_t idx, T value) const
- {
- auto p = node_t::copy_n(size, ptr, size);
- IMMER_TRY {
- p->data()[idx] = std::move(value);
- return {p, size};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, size);
- IMMER_RETHROW;
- }
- }
-
- template <typename Fn>
- no_capacity update(std::size_t idx, Fn&& op) const
- {
- auto p = node_t::copy_n(size, ptr, size);
- IMMER_TRY {
- auto& elem = p->data()[idx];
- elem = std::forward<Fn>(op)(std::move(elem));
- return {p, size};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, size);
- IMMER_RETHROW;
- }
- }
-
- no_capacity take(std::size_t sz) const
- {
- auto p = node_t::copy_n(sz, ptr, sz);
- return {p, sz};
- }
-};
-
-} // namespace arrays
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/arrays/node.hpp b/src/third_party/immer/dist/immer/detail/arrays/node.hpp
deleted file mode 100644
index ac521e03353..00000000000
--- a/src/third_party/immer/dist/immer/detail/arrays/node.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/combine_standard_layout.hpp>
-#include <immer/detail/type_traits.hpp>
-#include <immer/detail/util.hpp>
-
-#include <cstddef>
-#include <limits>
-
-namespace immer {
-namespace detail {
-namespace arrays {
-
-template <typename T, typename MemoryPolicy>
-struct node
-{
- using memory = MemoryPolicy;
- using heap = typename MemoryPolicy::heap::type;
- using transience = typename memory::transience_t;
- using refs_t = typename memory::refcount;
- using ownee_t = typename transience::ownee;
- using node_t = node;
- using edit_t = typename transience::edit;
-
- struct data_t
- {
- aligned_storage_for<T> buffer;
- };
-
- using impl_t = combine_standard_layout_t<data_t, refs_t, ownee_t>;
-
- impl_t impl;
-
- constexpr static std::size_t sizeof_n(size_t count)
- {
- return std::max(immer_offsetof(impl_t, d.buffer) + sizeof(T) * count,
- sizeof(node));
- }
-
- refs_t& refs() const { return auto_const_cast(get<refs_t>(impl)); }
-
- const ownee_t& ownee() const { return get<ownee_t>(impl); }
- ownee_t& ownee() { return get<ownee_t>(impl); }
-
- const T* data() const { return reinterpret_cast<const T*>(&impl.d.buffer); }
- T* data() { return reinterpret_cast<T*>(&impl.d.buffer); }
-
- bool can_mutate(edit_t e) const
- {
- return refs().unique() || ownee().can_mutate(e);
- }
-
- static void delete_n(node_t* p, size_t sz, size_t cap)
- {
- detail::destroy_n(p->data(), sz);
- heap::deallocate(sizeof_n(cap), p);
- }
-
- static node_t* make_n(size_t n)
- {
- return new (heap::allocate(sizeof_n(n))) node_t{};
- }
-
- static node_t* make_e(edit_t e, size_t n)
- {
- auto p = make_n(n);
- p->ownee() = e;
- return p;
- }
-
- static node_t* fill_n(size_t n, T v)
- {
- auto p = make_n(n);
- IMMER_TRY {
- std::uninitialized_fill_n(p->data(), n, v);
- return p;
- }
- IMMER_CATCH (...) {
- heap::deallocate(sizeof_n(n), p);
- IMMER_RETHROW;
- }
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- static node_t* copy_n(size_t n, Iter first, Sent last)
- {
- auto p = make_n(n);
- IMMER_TRY {
- detail::uninitialized_copy(first, last, p->data());
- return p;
- }
- IMMER_CATCH (...) {
- heap::deallocate(sizeof_n(n), p);
- IMMER_RETHROW;
- }
- }
-
- static node_t* copy_n(size_t n, node_t* p, size_t count)
- {
- return copy_n(n, p->data(), p->data() + count);
- }
-
- template <typename Iter>
- static node_t* copy_e(edit_t e, size_t n, Iter first, Iter last)
- {
- auto p = copy_n(n, first, last);
- p->ownee() = e;
- return p;
- }
-
- static node_t* copy_e(edit_t e, size_t n, node_t* p, size_t count)
- {
- return copy_e(e, n, p->data(), p->data() + count);
- }
-};
-
-} // namespace arrays
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/arrays/with_capacity.hpp b/src/third_party/immer/dist/immer/detail/arrays/with_capacity.hpp
deleted file mode 100644
index c80f7068219..00000000000
--- a/src/third_party/immer/dist/immer/detail/arrays/with_capacity.hpp
+++ /dev/null
@@ -1,317 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/arrays/no_capacity.hpp>
-
-#include <cassert>
-#include <cstddef>
-#include <stdexcept>
-
-namespace immer {
-namespace detail {
-namespace arrays {
-
-template <typename T, typename MemoryPolicy>
-struct with_capacity
-{
- using no_capacity_t = no_capacity<T, MemoryPolicy>;
-
- using node_t = node<T, MemoryPolicy>;
- using edit_t = typename MemoryPolicy::transience_t::edit;
- using size_t = std::size_t;
-
- node_t* ptr;
- size_t size;
- size_t capacity;
-
- static const with_capacity& empty()
- {
- static const with_capacity empty_{node_t::make_n(1), 0, 1};
- return empty_;
- }
-
- with_capacity(node_t* p, size_t s, size_t c)
- : ptr{p}
- , size{s}
- , capacity{c}
- {}
-
- with_capacity(const with_capacity& other)
- : with_capacity{other.ptr, other.size, other.capacity}
- {
- inc();
- }
-
- with_capacity(const no_capacity_t& other)
- : with_capacity{other.ptr, other.size, other.size}
- {
- inc();
- }
-
- with_capacity(with_capacity&& other)
- : with_capacity{empty()}
- {
- swap(*this, other);
- }
-
- with_capacity& operator=(const with_capacity& other)
- {
- auto next = other;
- swap(*this, next);
- return *this;
- }
-
- with_capacity& operator=(with_capacity&& other)
- {
- swap(*this, other);
- return *this;
- }
-
- friend void swap(with_capacity& x, with_capacity& y)
- {
- using std::swap;
- swap(x.ptr, y.ptr);
- swap(x.size, y.size);
- swap(x.capacity, y.capacity);
- }
-
- ~with_capacity() { dec(); }
-
- void inc()
- {
- using immer::detail::get;
- ptr->refs().inc();
- }
-
- void dec()
- {
- using immer::detail::get;
- if (ptr->refs().dec())
- node_t::delete_n(ptr, size, capacity);
- }
-
- const T* data() const { return ptr->data(); }
- T* data() { return ptr->data(); }
-
- T* data_mut(edit_t e)
- {
- if (!ptr->can_mutate(e)) {
- auto p = node_t::copy_e(e, capacity, ptr, size);
- dec();
- ptr = p;
- }
- return data();
- }
-
- operator no_capacity_t() const
- {
- if (size == capacity) {
- ptr->refs().inc();
- return {ptr, size};
- } else {
- return {node_t::copy_n(size, ptr, size), size};
- }
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<is_forward_iterator_v<Iter> &&
- compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- static with_capacity from_range(Iter first, Sent last)
- {
- auto count = static_cast<size_t>(distance(first, last));
- if (count == 0)
- return empty();
- else
- return {node_t::copy_n(count, first, last), count, count};
- }
-
- template <typename U>
- static with_capacity from_initializer_list(std::initializer_list<U> values)
- {
- using namespace std;
- return from_range(begin(values), end(values));
- }
-
- static with_capacity from_fill(size_t n, T v)
- {
- return {node_t::fill_n(n, v), n, n};
- }
-
- template <typename Fn>
- void for_each_chunk(Fn&& fn) const
- {
- std::forward<Fn>(fn)(data(), data() + size);
- }
-
- template <typename Fn>
- bool for_each_chunk_p(Fn&& fn) const
- {
- return std::forward<Fn>(fn)(data(), data() + size);
- }
-
- const T& get(std::size_t index) const { return data()[index]; }
-
- const T& get_check(std::size_t index) const
- {
- if (index >= size)
- IMMER_THROW(std::out_of_range{"out of range"});
- return data()[index];
- }
-
- bool equals(const with_capacity& other) const
- {
- return ptr == other.ptr ||
- (size == other.size &&
- std::equal(data(), data() + size, other.data()));
- }
-
- static size_t recommend_up(size_t sz, size_t cap)
- {
- auto max = std::numeric_limits<size_t>::max();
- return sz <= cap ? cap
- : cap >= max / 2 ? max
- /* otherwise */
- : std::max(2 * cap, sz);
- }
-
- static size_t recommend_down(size_t sz, size_t cap)
- {
- return sz == 0 ? 1
- : sz < cap / 2 ? sz * 2
- :
- /* otherwise */ cap;
- }
-
- with_capacity push_back(T value) const
- {
- auto cap = recommend_up(size + 1, capacity);
- auto p = node_t::copy_n(cap, ptr, size);
- IMMER_TRY {
- new (p->data() + size) T{std::move(value)};
- return {p, size + 1, cap};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, cap);
- IMMER_RETHROW;
- }
- }
-
- void push_back_mut(edit_t e, T value)
- {
- if (ptr->can_mutate(e) && capacity > size) {
- new (data() + size) T{std::move(value)};
- ++size;
- } else {
- auto cap = recommend_up(size + 1, capacity);
- auto p = node_t::copy_e(e, cap, ptr, size);
- IMMER_TRY {
- new (p->data() + size) T{std::move(value)};
- *this = {p, size + 1, cap};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, cap);
- IMMER_RETHROW;
- }
- }
- }
-
- with_capacity assoc(std::size_t idx, T value) const
- {
- auto p = node_t::copy_n(capacity, ptr, size);
- IMMER_TRY {
- p->data()[idx] = std::move(value);
- return {p, size, capacity};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, capacity);
- IMMER_RETHROW;
- }
- }
-
- void assoc_mut(edit_t e, std::size_t idx, T value)
- {
- if (ptr->can_mutate(e)) {
- data()[idx] = std::move(value);
- } else {
- auto p = node_t::copy_n(capacity, ptr, size);
- IMMER_TRY {
- p->data()[idx] = std::move(value);
- *this = {p, size, capacity};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, capacity);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename Fn>
- with_capacity update(std::size_t idx, Fn&& op) const
- {
- auto p = node_t::copy_n(capacity, ptr, size);
- IMMER_TRY {
- auto& elem = p->data()[idx];
- elem = std::forward<Fn>(op)(std::move(elem));
- return {p, size, capacity};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, capacity);
- IMMER_RETHROW;
- }
- }
-
- template <typename Fn>
- void update_mut(edit_t e, std::size_t idx, Fn&& op)
- {
- if (ptr->can_mutate(e)) {
- auto& elem = data()[idx];
- elem = std::forward<Fn>(op)(std::move(elem));
- } else {
- auto p = node_t::copy_e(e, capacity, ptr, size);
- IMMER_TRY {
- auto& elem = p->data()[idx];
- elem = std::forward<Fn>(op)(std::move(elem));
- *this = {p, size, capacity};
- }
- IMMER_CATCH (...) {
- node_t::delete_n(p, size, capacity);
- IMMER_RETHROW;
- }
- }
- }
-
- with_capacity take(std::size_t sz) const
- {
- assert(sz <= size);
- auto cap = recommend_down(sz, capacity);
- auto p = node_t::copy_n(cap, ptr, sz);
- return {p, sz, cap};
- }
-
- void take_mut(edit_t e, std::size_t sz)
- {
- assert(sz <= size);
- if (ptr->can_mutate(e)) {
- detail::destroy_n(data() + size, size - sz);
- size = sz;
- } else {
- auto cap = recommend_down(sz, capacity);
- auto p = node_t::copy_e(e, cap, ptr, sz);
- *this = {p, sz, cap};
- }
- }
-};
-
-} // namespace arrays
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/combine_standard_layout.hpp b/src/third_party/immer/dist/immer/detail/combine_standard_layout.hpp
deleted file mode 100644
index 68de2a8a8ce..00000000000
--- a/src/third_party/immer/dist/immer/detail/combine_standard_layout.hpp
+++ /dev/null
@@ -1,236 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstddef>
-#include <type_traits>
-
-#if defined(__GNUC__) && __GNUC__ == 7 && __GNUC_MINOR__ == 1
-#define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 1
-#define immer_offsetof(st, m) ((std::size_t) & (((st*) 0)->m))
-#else
-#define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 0
-#define immer_offsetof offsetof
-#endif
-
-namespace immer {
-namespace detail {
-
-//
-// Metafunction that returns a standard layout struct that combines
-// all the standard layout types in `Ts...`, while making sure that
-// empty base optimizations are used.
-//
-// To query a part of the type do `get<my_part>(x)`;
-//
-// This is useful when putting together a type that merges various
-// types coming from different policies. Some of them might be empty,
-// so we shall enable empty base optimizations. But if we just
-// inherit from all of them, we would break the "standard layout"
-// rules, preventing us from using `offseof(...)`. So metafunction
-// will generate the type by sometimes inheriting, sometimes adding as
-// member.
-//
-// Note that the types are added to the combined type from right to
-// left!
-//
-template <typename... Ts>
-struct combine_standard_layout;
-
-template <typename... Ts>
-using combine_standard_layout_t = typename combine_standard_layout<Ts...>::type;
-
-namespace csl {
-
-template <typename T>
-struct type_t
-{};
-
-template <typename U, typename T>
-U& get(T& x);
-
-template <typename U, typename T>
-const U& get(const T& x);
-
-template <typename T, typename Next = void>
-struct inherit
-{
- struct type
- : T
- , Next
- {
- using Next::get_;
-
- template <typename U>
- friend decltype(auto) get(type& x)
- {
- return x.get_(type_t<U>{});
- }
- template <typename U>
- friend decltype(auto) get(const type& x)
- {
- return x.get_(type_t<U>{});
- }
-
- T& get_(type_t<T>) { return *this; }
- const T& get_(type_t<T>) const { return *this; }
- };
-};
-
-template <typename T>
-struct inherit<T, void>
-{
- struct type : T
- {
- template <typename U>
- friend decltype(auto) get(type& x)
- {
- return x.get_(type_t<U>{});
- }
- template <typename U>
- friend decltype(auto) get(const type& x)
- {
- return x.get_(type_t<U>{});
- }
-
- T& get_(type_t<T>) { return *this; }
- const T& get_(type_t<T>) const { return *this; }
- };
-};
-
-template <typename T, typename Next = void>
-struct member
-{
- struct type : Next
- {
- T d;
-
- using Next::get_;
-
- template <typename U>
- friend decltype(auto) get(type& x)
- {
- return x.get_(type_t<U>{});
- }
- template <typename U>
- friend decltype(auto) get(const type& x)
- {
- return x.get_(type_t<U>{});
- }
-
- T& get_(type_t<T>) { return d; }
- const T& get_(type_t<T>) const { return d; }
- };
-};
-
-template <typename T>
-struct member<T, void>
-{
- struct type
- {
- T d;
-
- template <typename U>
- friend decltype(auto) get(type& x)
- {
- return x.get_(type_t<U>{});
- }
- template <typename U>
- friend decltype(auto) get(const type& x)
- {
- return x.get_(type_t<U>{});
- }
-
- T& get_(type_t<T>) { return d; }
- const T& get_(type_t<T>) const { return d; }
- };
-};
-
-template <typename T, typename Next>
-struct member_two
-{
- struct type
- {
- Next n;
- T d;
-
- template <typename U>
- friend decltype(auto) get(type& x)
- {
- return x.get_(type_t<U>{});
- }
- template <typename U>
- friend decltype(auto) get(const type& x)
- {
- return x.get_(type_t<U>{});
- }
-
- T& get_(type_t<T>) { return d; }
- const T& get_(type_t<T>) const { return d; }
-
- template <typename U>
- auto get_(type_t<U> t) -> decltype(auto)
- {
- return n.get_(t);
- }
- template <typename U>
- auto get_(type_t<U> t) const -> decltype(auto)
- {
- return n.get_(t);
- }
- };
-};
-
-template <typename... Ts>
-struct combine_standard_layout_aux;
-
-template <typename T>
-struct combine_standard_layout_aux<T>
-{
- static_assert(std::is_standard_layout<T>::value, "");
-
- using type = typename std::conditional_t<std::is_empty<T>::value,
- csl::inherit<T>,
- csl::member<T>>::type;
-};
-
-template <typename T, typename... Ts>
-struct combine_standard_layout_aux<T, Ts...>
-{
- static_assert(std::is_standard_layout<T>::value, "");
-
- using this_t = T;
- using next_t = typename combine_standard_layout_aux<Ts...>::type;
-
- static constexpr auto empty_this = std::is_empty<this_t>::value;
- static constexpr auto empty_next = std::is_empty<next_t>::value;
-
- using type = typename std::conditional_t<
- empty_this,
- inherit<this_t, next_t>,
- std::conditional_t<empty_next,
- member<this_t, next_t>,
- member_two<this_t, next_t>>>::type;
-};
-
-} // namespace csl
-
-using csl::get;
-
-template <typename... Ts>
-struct combine_standard_layout
-{
- using type = typename csl::combine_standard_layout_aux<Ts...>::type;
-#if !IMMER_BROKEN_STANDARD_LAYOUT_DETECTION
- static_assert(std::is_standard_layout<type>::value, "");
-#endif
-};
-
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/hamts/bits.hpp b/src/third_party/immer/dist/immer/detail/hamts/bits.hpp
deleted file mode 100644
index 0b4b9237846..00000000000
--- a/src/third_party/immer/dist/immer/detail/hamts/bits.hpp
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstddef>
-#include <cstdint>
-
-#if defined(_MSC_VER)
-#include <intrin.h> // __popcnt
-#endif
-
-namespace immer {
-namespace detail {
-namespace hamts {
-
-using size_t = std::size_t;
-using hash_t = std::size_t;
-using bits_t = std::uint32_t;
-using count_t = std::uint32_t;
-using shift_t = std::uint32_t;
-
-template <bits_t B>
-struct get_bitmap_type
-{
- static_assert(B < 6u, "B > 6 is not supported.");
- using type = std::uint8_t;
-};
-
-template <>
-struct get_bitmap_type<6u>
-{
- using type = std::uint64_t;
-};
-
-template <>
-struct get_bitmap_type<5u>
-{
- using type = std::uint32_t;
-};
-
-template <>
-struct get_bitmap_type<4u>
-{
- using type = std::uint16_t;
-};
-
-template <bits_t B, typename T = count_t>
-constexpr T branches = T{1u} << B;
-
-template <bits_t B, typename T = size_t>
-constexpr T mask = branches<B, T> - 1u;
-
-template <bits_t B, typename T = count_t>
-constexpr T max_depth = (sizeof(hash_t) * 8u + B - 1u) / B;
-
-template <bits_t B, typename T = count_t>
-constexpr T max_shift = max_depth<B, count_t>* B;
-
-#define IMMER_HAS_BUILTIN_POPCOUNT 1
-
-inline auto popcount_fallback(std::uint32_t x)
-{
- // More alternatives:
- // https://en.wikipedia.org/wiki/Hamming_weight
- // http://wm.ite.pl/articles/sse-popcount.html
- // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
- x = x - ((x >> 1) & 0x55555555u);
- x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
- return (((x + (x >> 4u)) & 0xF0F0F0Fu) * 0x1010101u) >> 24u;
-}
-
-inline auto popcount_fallback(std::uint64_t x)
-{
- x = x - ((x >> 1) & 0x5555555555555555u);
- x = (x & 0x3333333333333333u) + ((x >> 2u) & 0x3333333333333333u);
- return (((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Fu) * 0x0101010101010101u) >>
- 56u;
-}
-
-inline count_t popcount(std::uint32_t x)
-{
-#if IMMER_HAS_BUILTIN_POPCOUNT
-#if defined(_MSC_VER)
- return __popcnt(x);
-#else
- return __builtin_popcount(x);
-#endif
-#else
- return popcount_fallback(x);
-#endif
-}
-
-inline count_t popcount(std::uint64_t x)
-{
-#if IMMER_HAS_BUILTIN_POPCOUNT
-#if defined(_MSC_VER)
-#if defined(_WIN64)
- return static_cast<count_t>(__popcnt64(x));
-#else
- // TODO: benchmark against popcount_fallback(std::uint64_t x)
- return popcount(static_cast<std::uint32_t>(x >> 32)) +
- popcount(static_cast<std::uint32_t>(x));
-#endif
-#else
- return __builtin_popcountll(x);
-#endif
-#else
- return popcount_fallback(x);
-#endif
-}
-
-inline count_t popcount(std::uint16_t x)
-{
- return popcount(static_cast<std::uint32_t>(x));
-}
-
-inline count_t popcount(std::uint8_t x)
-{
- return popcount(static_cast<std::uint32_t>(x));
-}
-
-template <typename bitmap_t>
-class set_bits_range
-{
- bitmap_t bitmap;
-
- class set_bits_iterator
- {
- bitmap_t bitmap;
-
- inline static bitmap_t clearlsbit(bitmap_t bitmap)
- {
- return bitmap & (bitmap - 1);
- }
-
- inline static bitmap_t lsbit(bitmap_t bitmap)
- {
- return bitmap ^ clearlsbit(bitmap);
- }
-
- public:
- set_bits_iterator(bitmap_t bitmap)
- : bitmap(bitmap){};
-
- set_bits_iterator operator++()
- {
- bitmap = clearlsbit(bitmap);
- return *this;
- }
-
- bool operator!=(set_bits_iterator const& other) const
- {
- return bitmap != other.bitmap;
- }
-
- bitmap_t operator*() const { return lsbit(bitmap); }
- };
-
-public:
- set_bits_range(bitmap_t bitmap)
- : bitmap(bitmap)
- {}
- set_bits_iterator begin() const { return set_bits_iterator(bitmap); }
- set_bits_iterator end() const { return set_bits_iterator(0); }
-};
-
-} // namespace hamts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/hamts/champ.hpp b/src/third_party/immer/dist/immer/detail/hamts/champ.hpp
deleted file mode 100644
index 64a8cb82483..00000000000
--- a/src/third_party/immer/dist/immer/detail/hamts/champ.hpp
+++ /dev/null
@@ -1,1548 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/hamts/node.hpp>
-
-#include <algorithm>
-
-namespace immer {
-namespace detail {
-namespace hamts {
-
-#if IMMER_DEBUG_STATS
-struct champ_debug_stats
-{
- std::size_t bits = {};
- std::size_t value_size = {};
- std::size_t child_size = sizeof(void*);
-
- std::size_t inner_node_count = {};
- std::size_t inner_node_w_value_count = {};
- std::size_t inner_node_w_child_count = {};
- std::size_t collision_node_count = {};
-
- std::size_t child_count = {};
- std::size_t value_count = {};
- std::size_t collision_count = {};
-
- friend champ_debug_stats operator+(champ_debug_stats a, champ_debug_stats b)
- {
- if (a.bits != b.bits || a.value_size != b.value_size ||
- a.child_size != b.child_size)
- throw std::runtime_error{"accumulating incompatible stats"};
- return {
- a.bits,
- a.value_size,
- a.child_size,
- a.inner_node_count + b.inner_node_count,
- a.inner_node_w_value_count + b.inner_node_w_value_count,
- a.inner_node_w_child_count + b.inner_node_w_child_count,
- a.collision_node_count + b.collision_node_count,
- a.child_count + b.child_count,
- a.value_count + b.value_count,
- a.collision_count + b.collision_count,
- };
- }
-
- struct summary
- {
- double collision_ratio;
-
- double utilization;
- double child_utilization;
- double value_utilization;
-
- double dense_utilization;
- double dense_value_utilization;
- double dense_child_utilization;
-
- friend std::ostream& operator<<(std::ostream& os, const summary& s)
- {
- os << "---\n";
- os << "collisions\n"
- << " ratio = " << s.collision_ratio << " %\n";
- os << "utilization\n"
- << " total = " << s.utilization << " %\n"
- << " children = " << s.child_utilization << " %\n"
- << " values = " << s.value_utilization << " %\n";
- os << "utilization (dense)\n"
- << " total = " << s.dense_utilization << " %\n"
- << " children = " << s.dense_child_utilization << " %\n"
- << " values = " << s.dense_value_utilization << " %\n";
- return os;
- }
- };
-
- summary get_summary() const
- {
- auto m = std::size_t{1} << bits;
-
- auto collision_ratio = 100. * collision_count / value_count;
-
- auto capacity = m * inner_node_count;
- auto child_utilization = 100. * child_count / capacity;
- auto value_utilization = 100. * value_count / capacity;
- auto utilization =
- 100. * (value_count * value_size + child_count * child_size) /
- (capacity * value_size + capacity * child_size);
-
- auto value_capacity = m * inner_node_w_value_count;
- auto child_capacity = m * inner_node_w_child_count;
- auto dense_child_utilization =
- child_capacity == 0 ? 100. : 100. * child_count / child_capacity;
- auto dense_value_utilization =
- value_capacity == 0 ? 100. : 100. * value_count / value_capacity;
- auto dense_utilization =
- value_capacity + child_capacity == 0
- ? 100.
- : 100. * (value_count * value_size + child_count * child_size) /
- (value_capacity * value_size +
- child_capacity * child_size);
-
- return {collision_ratio,
- utilization,
- child_utilization,
- value_utilization,
- dense_utilization,
- dense_value_utilization,
- dense_child_utilization};
- }
-};
-#endif
-
-template <typename T,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- bits_t B>
-struct champ
-{
- static constexpr auto bits = B;
-
- using node_t = node<T, Hash, Equal, MemoryPolicy, B>;
- using edit_t = typename MemoryPolicy::transience_t::edit;
- using owner_t = typename MemoryPolicy::transience_t::owner;
- using bitmap_t = typename get_bitmap_type<B>::type;
-
- static_assert(branches<B> <= sizeof(bitmap_t) * 8, "");
-
- node_t* root;
- size_t size;
-
- static node_t* empty()
- {
- static const auto node = node_t::make_inner_n(0);
- return node->inc();
- }
-
- champ(node_t* r, size_t sz = 0)
- : root{r}
- , size{sz}
- {}
-
- champ(const champ& other)
- : champ{other.root, other.size}
- {
- inc();
- }
-
- champ(champ&& other)
- : champ{empty()}
- {
- swap(*this, other);
- }
-
- champ& operator=(const champ& other)
- {
- auto next = other;
- swap(*this, next);
- return *this;
- }
-
- champ& operator=(champ&& other)
- {
- swap(*this, other);
- return *this;
- }
-
- friend void swap(champ& x, champ& y)
- {
- using std::swap;
- swap(x.root, y.root);
- swap(x.size, y.size);
- }
-
- ~champ() { dec(); }
-
- void inc() const { root->inc(); }
-
- void dec() const
- {
- if (root->dec())
- node_t::delete_deep(root, 0);
- }
-
- std::size_t do_check_champ(node_t* node,
- count_t depth,
- size_t path_hash,
- size_t hash_mask) const
- {
- auto result = std::size_t{};
- if (depth < max_depth<B>) {
- auto nodemap = node->nodemap();
- if (nodemap) {
- auto fst = node->children();
- for (auto idx = std::size_t{}; idx < branches<B>; ++idx) {
- if (nodemap & (1 << idx)) {
- auto child = *fst++;
- result +=
- do_check_champ(child,
- depth + 1,
- path_hash | (idx << (B * depth)),
- (hash_mask << B) | mask<B>);
- }
- }
- }
- auto datamap = node->datamap();
- if (datamap) {
- auto fst = node->values();
- for (auto idx = std::size_t{}; idx < branches<B>; ++idx) {
- if (datamap & (1 << idx)) {
- auto hash = Hash{}(*fst++);
- auto check = (hash & hash_mask) ==
- (path_hash | (idx << (B * depth)));
- // assert(check);
- result += !!check;
- }
- }
- }
- } else {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst) {
- auto hash = Hash{}(*fst);
- auto check = hash == path_hash;
- // assert(check);
- result += !!check;
- }
- }
- return result;
- }
-
- // Checks that the hashes of the values correspond with what has actually
- // been inserted. If it doesn't it can mean that corruption has happened
- // due some value being moved out of the champ when it should have not.
- bool check_champ() const
- {
- auto r = do_check_champ(root, 0, 0, mask<B>);
- // assert(r == size);
- return r == size;
- }
-
-#if IMMER_DEBUG_STATS
- void do_get_debug_stats(champ_debug_stats& stats,
- node_t* node,
- count_t depth) const
- {
- if (depth < max_depth<B>) {
- ++stats.inner_node_count;
- stats.inner_node_w_value_count += node->data_count() > 0;
- stats.inner_node_w_child_count += node->children_count() > 0;
- stats.value_count += node->data_count();
- stats.child_count += node->children_count();
- auto nodemap = node->nodemap();
- if (nodemap) {
- auto fst = node->children();
- auto lst = fst + node->children_count();
- for (; fst != lst; ++fst)
- do_get_debug_stats(stats, *fst, depth + 1);
- }
- } else {
- ++stats.collision_node_count;
- stats.collision_count += node->collision_count();
- }
- }
-
- champ_debug_stats get_debug_stats() const
- {
- auto stats = champ_debug_stats{B, sizeof(T)};
- do_get_debug_stats(stats, root, 0);
- return stats;
- }
-#endif
-
- template <typename U>
- static auto from_initializer_list(std::initializer_list<U> values)
- {
- auto e = owner_t{};
- auto result = champ{empty()};
- for (auto&& v : values)
- result.add_mut(e, v);
- return result;
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<compatible_sentinel_v<Iter, Sent>, bool> = true>
- static auto from_range(Iter first, Sent last)
- {
- auto e = owner_t{};
- auto result = champ{empty()};
- for (; first != last; ++first)
- result.add_mut(e, *first);
- return result;
- }
-
- template <typename Fn>
- void for_each_chunk(Fn&& fn) const
- {
- for_each_chunk_traversal(root, 0, fn);
- }
-
- template <typename Fn>
- void
- for_each_chunk_traversal(const node_t* node, count_t depth, Fn&& fn) const
- {
- if (depth < max_depth<B>) {
- auto datamap = node->datamap();
- if (datamap)
- fn(node->values(), node->values() + node->data_count());
- auto nodemap = node->nodemap();
- if (nodemap) {
- auto fst = node->children();
- auto lst = fst + node->children_count();
- for (; fst != lst; ++fst)
- for_each_chunk_traversal(*fst, depth + 1, fn);
- }
- } else {
- fn(node->collisions(),
- node->collisions() + node->collision_count());
- }
- }
-
- template <typename EqualValue, typename Differ>
- void diff(const champ& new_champ, Differ&& differ) const
- {
- diff<EqualValue>(root, new_champ.root, 0, std::forward<Differ>(differ));
- }
-
- template <typename EqualValue, typename Differ>
- void diff(const node_t* old_node,
- const node_t* new_node,
- count_t depth,
- Differ&& differ) const
- {
- if (old_node == new_node)
- return;
- if (depth < max_depth<B>) {
- auto old_nodemap = old_node->nodemap();
- auto new_nodemap = new_node->nodemap();
- auto old_datamap = old_node->datamap();
- auto new_datamap = new_node->datamap();
- auto old_bits = old_nodemap | old_datamap;
- auto new_bits = new_nodemap | new_datamap;
- auto changes = old_bits ^ new_bits;
-
- // added bits
- for (auto bit : set_bits_range<bitmap_t>(new_bits & changes)) {
- if (new_nodemap & bit) {
- auto offset = new_node->children_count(bit);
- auto child = new_node->children()[offset];
- for_each_chunk_traversal(
- child,
- depth + 1,
- [&](auto const& begin, auto const& end) {
- for (auto it = begin; it != end; it++)
- differ.added(*it);
- });
- } else if (new_datamap & bit) {
- auto offset = new_node->data_count(bit);
- auto const& value = new_node->values()[offset];
- differ.added(value);
- }
- }
-
- // removed bits
- for (auto bit : set_bits_range<bitmap_t>(old_bits & changes)) {
- if (old_nodemap & bit) {
- auto offset = old_node->children_count(bit);
- auto child = old_node->children()[offset];
- for_each_chunk_traversal(
- child,
- depth + 1,
- [&](auto const& begin, auto const& end) {
- for (auto it = begin; it != end; it++)
- differ.removed(*it);
- });
- } else if (old_datamap & bit) {
- auto offset = old_node->data_count(bit);
- auto const& value = old_node->values()[offset];
- differ.removed(value);
- }
- }
-
- // bits in both nodes
- for (auto bit : set_bits_range<bitmap_t>(old_bits & new_bits)) {
- if ((old_nodemap & bit) && (new_nodemap & bit)) {
- auto old_offset = old_node->children_count(bit);
- auto new_offset = new_node->children_count(bit);
- auto old_child = old_node->children()[old_offset];
- auto new_child = new_node->children()[new_offset];
- diff<EqualValue>(old_child, new_child, depth + 1, differ);
- } else if ((old_datamap & bit) && (new_nodemap & bit)) {
- diff_data_node<EqualValue>(
- old_node, new_node, bit, depth, differ);
- } else if ((old_nodemap & bit) && (new_datamap & bit)) {
- diff_node_data<EqualValue>(
- old_node, new_node, bit, depth, differ);
- } else if ((old_datamap & bit) && (new_datamap & bit)) {
- diff_data_data<EqualValue>(old_node, new_node, bit, differ);
- }
- }
- } else {
- diff_collisions<EqualValue>(old_node, new_node, differ);
- }
- }
-
- template <typename EqualValue, typename Differ>
- void diff_data_node(const node_t* old_node,
- const node_t* new_node,
- bitmap_t bit,
- count_t depth,
- Differ&& differ) const
- {
- auto old_offset = old_node->data_count(bit);
- auto const& old_value = old_node->values()[old_offset];
- auto new_offset = new_node->children_count(bit);
- auto new_child = new_node->children()[new_offset];
-
- bool found = false;
- for_each_chunk_traversal(
- new_child, depth + 1, [&](auto const& begin, auto const& end) {
- for (auto it = begin; it != end; it++) {
- if (Equal{}(old_value, *it)) {
- if (!EqualValue{}(old_value, *it))
- differ.changed(old_value, *it);
- found = true;
- } else {
- differ.added(*it);
- }
- }
- });
- if (!found)
- differ.removed(old_value);
- }
-
- template <typename EqualValue, typename Differ>
- void diff_node_data(const node_t* old_node,
- const node_t* const new_node,
- bitmap_t bit,
- count_t depth,
- Differ&& differ) const
- {
- auto old_offset = old_node->children_count(bit);
- auto old_child = old_node->children()[old_offset];
- auto new_offset = new_node->data_count(bit);
- auto const& new_value = new_node->values()[new_offset];
-
- bool found = false;
- for_each_chunk_traversal(
- old_child, depth + 1, [&](auto const& begin, auto const& end) {
- for (auto it = begin; it != end; it++) {
- if (Equal{}(*it, new_value)) {
- if (!EqualValue{}(*it, new_value))
- differ.changed(*it, new_value);
- found = true;
- } else {
- differ.removed(*it);
- }
- }
- });
- if (!found)
- differ.added(new_value);
- }
-
- template <typename EqualValue, typename Differ>
- void diff_data_data(const node_t* old_node,
- const node_t* new_node,
- bitmap_t bit,
- Differ&& differ) const
- {
- auto old_offset = old_node->data_count(bit);
- auto new_offset = new_node->data_count(bit);
- auto const& old_value = old_node->values()[old_offset];
- auto const& new_value = new_node->values()[new_offset];
- if (!Equal{}(old_value, new_value)) {
- differ.removed(old_value);
- differ.added(new_value);
- } else {
- if (!EqualValue{}(old_value, new_value))
- differ.changed(old_value, new_value);
- }
- }
-
- template <typename EqualValue, typename Differ>
- void diff_collisions(const node_t* old_node,
- const node_t* new_node,
- Differ&& differ) const
- {
- auto old_begin = old_node->collisions();
- auto old_end = old_node->collisions() + old_node->collision_count();
- auto new_begin = new_node->collisions();
- auto new_end = new_node->collisions() + new_node->collision_count();
- // search changes and removals
- for (auto old_it = old_begin; old_it != old_end; old_it++) {
- bool found = false;
- for (auto new_it = new_begin; new_it != new_end; new_it++) {
- if (Equal{}(*old_it, *new_it)) {
- if (!EqualValue{}(*old_it, *new_it))
- differ.changed(*old_it, *new_it);
- found = true;
- break;
- }
- }
- if (!found)
- differ.removed(*old_it);
- }
- // search new entries
- for (auto new_it = new_begin; new_it != new_end; new_it++) {
- bool found = false;
- for (auto old_it = old_begin; old_it != old_end; old_it++) {
- if (Equal{}(*old_it, *new_it)) {
- found = true;
- break;
- }
- }
- if (!found)
- differ.added(*new_it);
- }
- }
-
- template <typename Project, typename Default, typename K>
- decltype(auto) get(const K& k) const
- {
- auto node = root;
- auto hash = Hash{}(k);
- for (auto i = count_t{}; i < max_depth<B>; ++i) {
- auto bit = bitmap_t{1u} << (hash & mask<B>);
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- node = node->children()[offset];
- hash = hash >> B;
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k))
- return Project{}(*val);
- else
- return Default{}();
- } else {
- return Default{}();
- }
- }
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, k))
- return Project{}(*fst);
- return Default{}();
- }
-
- struct add_result
- {
- node_t* node;
- bool added;
- };
-
- add_result do_add(node_t* node, T v, hash_t hash, shift_t shift) const
- {
- assert(node);
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, v))
- return {
- node_t::copy_collision_replace(node, fst, std::move(v)),
- false};
- return {node_t::copy_collision_insert(node, std::move(v)), true};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- assert(node->children()[offset]);
- auto result = do_add(
- node->children()[offset], std::move(v), hash, shift + B);
- IMMER_TRY {
- result.node =
- node_t::copy_inner_replace(node, offset, result.node);
- return result;
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.node, shift + B);
- IMMER_RETHROW;
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, v))
- return {node_t::copy_inner_replace_value(
- node, offset, std::move(v)),
- false};
- else {
- auto child = node_t::make_merged(
- shift + B, std::move(v), hash, *val, Hash{}(*val));
- IMMER_TRY {
- return {node_t::copy_inner_replace_merged(
- node, bit, offset, child),
- true};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(child, shift + B);
- IMMER_RETHROW;
- }
- }
- } else {
- return {
- node_t::copy_inner_insert_value(node, bit, std::move(v)),
- true};
- }
- }
- }
-
- champ add(T v) const
- {
- auto hash = Hash{}(v);
- auto res = do_add(root, std::move(v), hash, 0);
- auto new_size = size + (res.added ? 1 : 0);
- return {res.node, new_size};
- }
-
- struct add_mut_result
- {
- node_t* node;
- bool added;
- bool mutated;
- };
-
- add_mut_result
- do_add_mut(edit_t e, node_t* node, T v, hash_t hash, shift_t shift) const
- {
- assert(node);
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, v)) {
- if (node->can_mutate(e)) {
- *fst = std::move(v);
- return {node, false, true};
- } else {
- auto r = node_t::copy_collision_replace(
- node, fst, std::move(v));
- return {node_t::owned(r, e), false, false};
- }
- }
- auto mutate = node->can_mutate(e);
- auto r = mutate ? node_t::move_collision_insert(node, std::move(v))
- : node_t::copy_collision_insert(node, std::move(v));
- return {node_t::owned(r, e), true, mutate};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto child = node->children()[offset];
- if (node->can_mutate(e)) {
- auto result =
- do_add_mut(e, child, std::move(v), hash, shift + B);
- node->children()[offset] = result.node;
- if (!result.mutated && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- return {node, result.added, true};
- } else {
- assert(node->children()[offset]);
- auto result = do_add(child, std::move(v), hash, shift + B);
- IMMER_TRY {
- result.node = node_t::copy_inner_replace(
- node, offset, result.node);
- node_t::owned(result.node, e);
- return {result.node, result.added, false};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.node, shift + B);
- IMMER_RETHROW;
- }
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, v)) {
- if (node->can_mutate(e)) {
- auto vals = node->ensure_mutable_values(e);
- vals[offset] = std::move(v);
- return {node, false, true};
- } else {
- auto r = node_t::copy_inner_replace_value(
- node, offset, std::move(v));
- return {node_t::owned_values(r, e), false, false};
- }
- } else {
- auto mutate = node->can_mutate(e);
- auto mutate_values = mutate && node->can_mutate_values(e);
- auto hash2 = Hash{}(*val);
- auto child = node_t::make_merged_e(
- e,
- shift + B,
- std::move(v),
- hash,
- mutate_values ? std::move(*val) : *val,
- hash2);
- IMMER_TRY {
- auto r = mutate ? node_t::move_inner_replace_merged(
- e, node, bit, offset, child)
- : node_t::copy_inner_replace_merged(
- node, bit, offset, child);
- return {node_t::owned_values_safe(r, e), true, mutate};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(child, shift + B);
- IMMER_RETHROW;
- }
- }
- } else {
- auto mutate = node->can_mutate(e);
- auto r = mutate ? node_t::move_inner_insert_value(
- e, node, bit, std::move(v))
- : node_t::copy_inner_insert_value(
- node, bit, std::move(v));
- return {node_t::owned_values(r, e), true, mutate};
- }
- }
- }
-
- void add_mut(edit_t e, T v)
- {
- auto hash = Hash{}(v);
- auto res = do_add_mut(e, root, std::move(v), hash, 0);
- if (!res.mutated && root->dec())
- node_t::delete_deep(root, 0);
- root = res.node;
- size += res.added ? 1 : 0;
- }
-
- using update_result = add_result;
-
- template <typename Project,
- typename Default,
- typename Combine,
- typename K,
- typename Fn>
- update_result
- do_update(node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
- {
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, k))
- return {node_t::copy_collision_replace(
- node,
- fst,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(
- detail::as_const(*fst))))),
- false};
- return {node_t::copy_collision_insert(
- node,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}()))),
- true};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto result = do_update<Project, Default, Combine>(
- node->children()[offset],
- k,
- std::forward<Fn>(fn),
- hash,
- shift + B);
- IMMER_TRY {
- result.node =
- node_t::copy_inner_replace(node, offset, result.node);
- return result;
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.node, shift + B);
- IMMER_RETHROW;
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k))
- return {node_t::copy_inner_replace_value(
- node,
- offset,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(
- detail::as_const(*val))))),
- false};
- else {
- auto child = node_t::make_merged(
- shift + B,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}())),
- hash,
- *val,
- Hash{}(*val));
- IMMER_TRY {
- return {node_t::copy_inner_replace_merged(
- node, bit, offset, child),
- true};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(child, shift + B);
- IMMER_RETHROW;
- }
- }
- } else {
- return {node_t::copy_inner_insert_value(
- node,
- bit,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}()))),
- true};
- }
- }
- }
-
- template <typename Project,
- typename Default,
- typename Combine,
- typename K,
- typename Fn>
- champ update(const K& k, Fn&& fn) const
- {
- auto hash = Hash{}(k);
- auto res = do_update<Project, Default, Combine>(
- root, k, std::forward<Fn>(fn), hash, 0);
- auto new_size = size + (res.added ? 1 : 0);
- return {res.node, new_size};
- }
-
- template <typename Project, typename Combine, typename K, typename Fn>
- node_t* do_update_if_exists(
- node_t* node, K&& k, Fn&& fn, hash_t hash, shift_t shift) const
- {
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, k))
- return node_t::copy_collision_replace(
- node,
- fst,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*fst)))));
- return nullptr;
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto result = do_update_if_exists<Project, Combine>(
- node->children()[offset],
- k,
- std::forward<Fn>(fn),
- hash,
- shift + B);
- IMMER_TRY {
- return result ? node_t::copy_inner_replace(
- node, offset, result)
- : nullptr;
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result, shift + B);
- IMMER_RETHROW;
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k))
- return node_t::copy_inner_replace_value(
- node,
- offset,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*val)))));
- else {
- return nullptr;
- }
- } else {
- return nullptr;
- }
- }
- }
-
- template <typename Project, typename Combine, typename K, typename Fn>
- champ update_if_exists(const K& k, Fn&& fn) const
- {
- auto hash = Hash{}(k);
- auto res = do_update_if_exists<Project, Combine>(
- root, k, std::forward<Fn>(fn), hash, 0);
- if (res) {
- return {res, size};
- } else {
- return {root->inc(), size};
- };
- }
-
- using update_mut_result = add_mut_result;
-
- template <typename Project,
- typename Default,
- typename Combine,
- typename K,
- typename Fn>
- update_mut_result do_update_mut(edit_t e,
- node_t* node,
- K&& k,
- Fn&& fn,
- hash_t hash,
- shift_t shift) const
- {
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, k)) {
- if (node->can_mutate(e)) {
- *fst = Combine{}(
- std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(std::move(*fst))));
- return {node, false, true};
- } else {
- auto r = node_t::copy_collision_replace(
- node,
- fst,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*fst)))));
- return {node_t::owned(r, e), false, false};
- }
- }
- auto v = Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}()));
- auto mutate = node->can_mutate(e);
- auto r = mutate ? node_t::move_collision_insert(node, std::move(v))
- : node_t::copy_collision_insert(node, std::move(v));
- return {node_t::owned(r, e), true, mutate};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto child = node->children()[offset];
- if (node->can_mutate(e)) {
- auto result = do_update_mut<Project, Default, Combine>(
- e, child, k, std::forward<Fn>(fn), hash, shift + B);
- node->children()[offset] = result.node;
- if (!result.mutated && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- return {node, result.added, true};
- } else {
- auto result = do_update<Project, Default, Combine>(
- child, k, std::forward<Fn>(fn), hash, shift + B);
- IMMER_TRY {
- result.node = node_t::copy_inner_replace(
- node, offset, result.node);
- node_t::owned(result.node, e);
- return {result.node, result.added, false};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.node, shift + B);
- IMMER_RETHROW;
- }
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k)) {
- if (node->can_mutate(e)) {
- auto vals = node->ensure_mutable_values(e);
- vals[offset] = Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(
- std::move(vals[offset]))));
- return {node, false, true};
- } else {
- auto r = node_t::copy_inner_replace_value(
- node,
- offset,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*val)))));
- return {node_t::owned_values(r, e), false, false};
- }
- } else {
- auto mutate = node->can_mutate(e);
- auto mutate_values = mutate && node->can_mutate_values(e);
- auto hash2 = Hash{}(*val);
- auto child = node_t::make_merged_e(
- e,
- shift + B,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}())),
- hash,
- mutate_values ? std::move(*val) : *val,
- hash2);
- IMMER_TRY {
- auto r = mutate ? node_t::move_inner_replace_merged(
- e, node, bit, offset, child)
- : node_t::copy_inner_replace_merged(
- node, bit, offset, child);
- return {node_t::owned_values_safe(r, e), true, mutate};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(child, shift + B);
- IMMER_RETHROW;
- }
- }
- } else {
- auto mutate = node->can_mutate(e);
- auto v = Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Default{}()));
- auto r = mutate ? node_t::move_inner_insert_value(
- e, node, bit, std::move(v))
- : node_t::copy_inner_insert_value(
- node, bit, std::move(v));
- return {node_t::owned_values(r, e), true, mutate};
- }
- }
- }
-
- template <typename Project,
- typename Default,
- typename Combine,
- typename K,
- typename Fn>
- void update_mut(edit_t e, const K& k, Fn&& fn)
- {
- auto hash = Hash{}(k);
- auto res = do_update_mut<Project, Default, Combine>(
- e, root, k, std::forward<Fn>(fn), hash, 0);
- if (!res.mutated && root->dec())
- node_t::delete_deep(root, 0);
- root = res.node;
- size += res.added ? 1 : 0;
- }
-
- struct update_if_exists_mut_result
- {
- node_t* node;
- bool mutated;
- };
-
- template <typename Project, typename Combine, typename K, typename Fn>
- update_if_exists_mut_result do_update_if_exists_mut(edit_t e,
- node_t* node,
- K&& k,
- Fn&& fn,
- hash_t hash,
- shift_t shift) const
- {
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (; fst != lst; ++fst)
- if (Equal{}(*fst, k)) {
- if (node->can_mutate(e)) {
- *fst = Combine{}(
- std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(std::move(*fst))));
- return {node, true};
- } else {
- auto r = node_t::copy_collision_replace(
- node,
- fst,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*fst)))));
- return {node_t::owned(r, e), false};
- }
- }
- return {nullptr, false};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto child = node->children()[offset];
- if (node->can_mutate(e)) {
- auto result = do_update_if_exists_mut<Project, Combine>(
- e, child, k, std::forward<Fn>(fn), hash, shift + B);
- if (result.node) {
- node->children()[offset] = result.node;
- if (!result.mutated && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- return {node, true};
- } else {
- return {nullptr, false};
- }
- } else {
- auto result = do_update_if_exists<Project, Combine>(
- child, k, std::forward<Fn>(fn), hash, shift + B);
- IMMER_TRY {
- if (result) {
- result = node_t::copy_inner_replace(
- node, offset, result);
- node_t::owned(result, e);
- return {result, false};
- } else {
- return {nullptr, false};
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result, shift + B);
- IMMER_RETHROW;
- }
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k)) {
- if (node->can_mutate(e)) {
- auto vals = node->ensure_mutable_values(e);
- vals[offset] = Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(Project{}(
- std::move(vals[offset]))));
- return {node, true};
- } else {
- auto r = node_t::copy_inner_replace_value(
- node,
- offset,
- Combine{}(std::forward<K>(k),
- std::forward<Fn>(fn)(
- Project{}(detail::as_const(*val)))));
- return {node_t::owned_values(r, e), false};
- }
- } else {
- return {nullptr, false};
- }
- } else {
- return {nullptr, false};
- }
- }
- }
-
- template <typename Project, typename Combine, typename K, typename Fn>
- void update_if_exists_mut(edit_t e, const K& k, Fn&& fn)
- {
- auto hash = Hash{}(k);
- auto res = do_update_if_exists_mut<Project, Combine>(
- e, root, k, std::forward<Fn>(fn), hash, 0);
- if (res.node) {
- if (!res.mutated && root->dec())
- node_t::delete_deep(root, 0);
- root = res.node;
- }
- }
-
- // basically:
- // variant<monostate_t, T*, node_t*>
- // boo bad we are not using... C++17 :'(
- struct sub_result
- {
- enum kind_t
- {
- nothing,
- singleton,
- tree
- };
-
- union data_t
- {
- T* singleton;
- node_t* tree;
- };
-
- kind_t kind;
- data_t data;
-
- sub_result()
- : kind{nothing} {};
- sub_result(T* x)
- : kind{singleton}
- {
- data.singleton = x;
- };
- sub_result(node_t* x)
- : kind{tree}
- {
- data.tree = x;
- };
- };
-
- template <typename K>
- sub_result
- do_sub(node_t* node, const K& k, hash_t hash, shift_t shift) const
- {
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (auto cur = fst; cur != lst; ++cur)
- if (Equal{}(*cur, k))
- return node->collision_count() > 2
- ? node_t::copy_collision_remove(node, cur)
- : sub_result{fst + (cur == fst)};
-#if !defined(_MSC_VER)
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
-#endif
- // Apparently GCC is generating this warning sometimes when
- // compiling the benchmarks. It makes however no sense at all.
- return {};
-#if !defined(_MSC_VER)
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-#endif
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto result =
- do_sub(node->children()[offset], k, hash, shift + B);
- switch (result.kind) {
- case sub_result::nothing:
- return {};
- case sub_result::singleton:
- return node->datamap() == 0 &&
- node->children_count() == 1 && shift > 0
- ? result
- : node_t::copy_inner_replace_inline(
- node, bit, offset, *result.data.singleton);
- case sub_result::tree:
- IMMER_TRY {
- return node_t::copy_inner_replace(
- node, offset, result.data.tree);
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.data.tree, shift + B);
- IMMER_RETHROW;
- }
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- if (Equal{}(*val, k)) {
- auto nv = node->data_count();
- if (node->nodemap() || nv > 2)
- return node_t::copy_inner_remove_value(
- node, bit, offset);
- else if (nv == 2) {
- return shift > 0 ? sub_result{node->values() + !offset}
- : node_t::make_inner_n(
- 0,
- node->datamap() & ~bit,
- node->values()[!offset]);
- } else {
- assert(shift == 0);
- return empty();
- }
- }
- }
- return {};
- }
- }
-
- template <typename K>
- champ sub(const K& k) const
- {
- auto hash = Hash{}(k);
- auto res = do_sub(root, k, hash, 0);
- switch (res.kind) {
- case sub_result::nothing:
- return *this;
- case sub_result::tree:
- return {res.data.tree, size - 1};
- default:
- IMMER_UNREACHABLE;
- }
- }
-
- struct sub_result_mut
- {
- using kind_t = typename sub_result::kind_t;
- using data_t = typename sub_result::data_t;
-
- kind_t kind;
- data_t data;
- bool owned;
- bool mutated;
-
- sub_result_mut(sub_result a)
- : kind{a.kind}
- , data{a.data}
- , owned{false}
- , mutated{false}
- {}
- sub_result_mut(sub_result a, bool m)
- : kind{a.kind}
- , data{a.data}
- , owned{false}
- , mutated{m}
- {}
- sub_result_mut()
- : kind{kind_t::nothing}
- , mutated{false} {};
- sub_result_mut(T* x, bool m)
- : kind{kind_t::singleton}
- , owned{m}
- , mutated{m}
- {
- data.singleton = x;
- };
- sub_result_mut(T* x, bool o, bool m)
- : kind{kind_t::singleton}
- , owned{o}
- , mutated{m}
- {
- data.singleton = x;
- };
- sub_result_mut(node_t* x, bool m)
- : kind{kind_t::tree}
- , owned{false}
- , mutated{m}
- {
- data.tree = x;
- };
- };
-
- template <typename K>
- sub_result_mut do_sub_mut(edit_t e,
- node_t* node,
- const K& k,
- hash_t hash,
- shift_t shift,
- void* store) const
- {
- auto mutate = node->can_mutate(e);
- if (shift == max_shift<B>) {
- auto fst = node->collisions();
- auto lst = fst + node->collision_count();
- for (auto cur = fst; cur != lst; ++cur) {
- if (Equal{}(*cur, k)) {
- if (node->collision_count() <= 2) {
- if (mutate) {
- auto r = new (store)
- T{std::move(node->collisions()[cur == fst])};
- node_t::delete_collision(node);
- return sub_result_mut{r, true};
- } else {
- return sub_result_mut{fst + (cur == fst), false};
- }
- } else {
- auto r = mutate
- ? node_t::move_collision_remove(node, cur)
- : node_t::copy_collision_remove(node, cur);
- return {node_t::owned(r, e), mutate};
- }
- }
- }
- return {};
- } else {
- auto idx = (hash & (mask<B> << shift)) >> shift;
- auto bit = bitmap_t{1u} << idx;
- if (node->nodemap() & bit) {
- auto offset = node->children_count(bit);
- auto children = node->children();
- auto child = children[offset];
- auto result =
- mutate ? do_sub_mut(e, child, k, hash, shift + B, store)
- : do_sub(child, k, hash, shift + B);
- switch (result.kind) {
- case sub_result::nothing:
- return {};
- case sub_result::singleton:
- if (node->datamap() == 0 && node->children_count() == 1 &&
- shift > 0) {
- if (mutate) {
- node_t::delete_inner(node);
- if (!result.mutated && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- }
- return {result.data.singleton, result.owned, mutate};
- } else {
- auto r =
- mutate ? node_t::move_inner_replace_inline(
- e,
- node,
- bit,
- offset,
- result.owned
- ? std::move(*result.data.singleton)
- : *result.data.singleton)
- : node_t::copy_inner_replace_inline(
- node,
- bit,
- offset,
- *result.data.singleton);
- if (result.owned)
- detail::destroy_at(result.data.singleton);
- if (!result.mutated && mutate && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- return {node_t::owned_values(r, e), mutate};
- }
- case sub_result::tree:
- if (mutate) {
- children[offset] = result.data.tree;
- if (!result.mutated && child->dec())
- node_t::delete_deep_shift(child, shift + B);
- return {node, true};
- } else {
- IMMER_TRY {
- auto r = node_t::copy_inner_replace(
- node, offset, result.data.tree);
- return {node_t::owned(r, e), false};
- }
- IMMER_CATCH (...) {
- node_t::delete_deep_shift(result.data.tree,
- shift + B);
- IMMER_RETHROW;
- }
- }
- }
- } else if (node->datamap() & bit) {
- auto offset = node->data_count(bit);
- auto val = node->values() + offset;
- auto mutate_values = mutate && node->can_mutate_values(e);
- if (Equal{}(*val, k)) {
- auto nv = node->data_count();
- if (node->nodemap() || nv > 2) {
- auto r = mutate ? node_t::move_inner_remove_value(
- e, node, bit, offset)
- : node_t::copy_inner_remove_value(
- node, bit, offset);
- return {node_t::owned_values_safe(r, e), mutate};
- } else if (nv == 2) {
- if (shift > 0) {
- if (mutate_values) {
- auto r = new (store)
- T{std::move(node->values()[!offset])};
- node_t::delete_inner(node);
- return {r, true};
- } else {
- return {node->values() + !offset, false};
- }
- } else {
- auto& v = node->values()[!offset];
- auto r = node_t::make_inner_n(
- 0,
- node->datamap() & ~bit,
- mutate_values ? std::move(v) : v);
- assert(!node->nodemap());
- if (mutate)
- node_t::delete_inner(node);
- return {node_t::owned_values(r, e), mutate};
- }
- } else {
- assert(shift == 0);
- if (mutate)
- node_t::delete_inner(node);
- return {empty(), mutate};
- }
- }
- }
- return {};
- }
- }
-
- template <typename K>
- void sub_mut(edit_t e, const K& k)
- {
- auto store = aligned_storage_for<T>{};
- auto hash = Hash{}(k);
- auto res = do_sub_mut(e, root, k, hash, 0, &store);
- switch (res.kind) {
- case sub_result::nothing:
- break;
- case sub_result::tree:
- if (!res.mutated && root->dec())
- node_t::delete_deep(root, 0);
- root = res.data.tree;
- --size;
- break;
- default:
- IMMER_UNREACHABLE;
- }
- }
-
- template <typename Eq = Equal>
- bool equals(const champ& other) const
- {
- return size == other.size && equals_tree<Eq>(root, other.root, 0);
- }
-
- template <typename Eq>
- static bool equals_tree(const node_t* a, const node_t* b, count_t depth)
- {
- if (a == b)
- return true;
- else if (depth == max_depth<B>) {
- auto nv = a->collision_count();
- return nv == b->collision_count() &&
- equals_collisions<Eq>(a->collisions(), b->collisions(), nv);
- } else {
- if (a->nodemap() != b->nodemap() || a->datamap() != b->datamap())
- return false;
- auto n = a->children_count();
- for (auto i = count_t{}; i < n; ++i)
- if (!equals_tree<Eq>(
- a->children()[i], b->children()[i], depth + 1))
- return false;
- auto nv = a->data_count();
- return !nv || equals_values<Eq>(a->values(), b->values(), nv);
- }
- }
-
- template <typename Eq>
- static bool equals_values(const T* a, const T* b, count_t n)
- {
- return std::equal(a, a + n, b, Eq{});
- }
-
- template <typename Eq>
- static bool equals_collisions(const T* a, const T* b, count_t n)
- {
- auto ae = a + n;
- auto be = b + n;
- for (; a != ae; ++a) {
- for (auto fst = b; fst != be; ++fst)
- if (Eq{}(*a, *fst))
- goto good;
- return false;
- good:
- continue;
- }
- return true;
- }
-};
-
-} // namespace hamts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/hamts/champ_iterator.hpp b/src/third_party/immer/dist/immer/detail/hamts/champ_iterator.hpp
deleted file mode 100644
index 373198bb03c..00000000000
--- a/src/third_party/immer/dist/immer/detail/hamts/champ_iterator.hpp
+++ /dev/null
@@ -1,151 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/detail/iterator_facade.hpp>
-
-namespace immer {
-namespace detail {
-namespace hamts {
-
-template <typename T, typename Hash, typename Eq, typename MP, bits_t B>
-struct champ_iterator
- : iterator_facade<champ_iterator<T, Hash, Eq, MP, B>,
- std::forward_iterator_tag,
- T,
- const T&,
- std::ptrdiff_t,
- const T*>
-{
- using tree_t = champ<T, Hash, Eq, MP, B>;
- using node_t = typename tree_t::node_t;
-
- struct end_t
- {};
-
- champ_iterator(const tree_t& v)
- : depth_{0}
- {
- if (v.root->datamap()) {
- cur_ = v.root->values();
- end_ = v.root->values() + v.root->data_count();
- } else {
- cur_ = end_ = nullptr;
- }
- path_[0] = &v.root;
- ensure_valid_();
- }
-
- champ_iterator(const tree_t& v, end_t)
- : cur_{nullptr}
- , end_{nullptr}
- , depth_{0}
- {
- path_[0] = &v.root;
- }
-
- champ_iterator(const champ_iterator& other)
- : cur_{other.cur_}
- , end_{other.end_}
- , depth_{other.depth_}
- {
- std::copy(other.path_, other.path_ + depth_ + 1, path_);
- }
-
-private:
- friend iterator_core_access;
-
- T* cur_;
- T* end_;
- count_t depth_;
- node_t* const* path_[max_depth<B> + 1] = {
- 0,
- };
-
- void increment()
- {
- ++cur_;
- ensure_valid_();
- }
-
- bool step_down()
- {
- if (depth_ < max_depth<B>) {
- auto parent = *path_[depth_];
- assert(parent);
- if (parent->nodemap()) {
- ++depth_;
- path_[depth_] = parent->children();
- auto child = *path_[depth_];
- assert(child);
- if (depth_ < max_depth<B>) {
- if (child->datamap()) {
- cur_ = child->values();
- end_ = cur_ + child->data_count();
- }
- } else {
- cur_ = child->collisions();
- end_ = cur_ + child->collision_count();
- }
- return true;
- }
- }
- return false;
- }
-
- bool step_right()
- {
- while (depth_ > 0) {
- auto parent = *path_[depth_ - 1];
- auto last = parent->children() + parent->children_count();
- auto next = path_[depth_] + 1;
- if (next < last) {
- path_[depth_] = next;
- auto child = *path_[depth_];
- assert(child);
- if (depth_ < max_depth<B>) {
- if (child->datamap()) {
- cur_ = child->values();
- end_ = cur_ + child->data_count();
- }
- } else {
- cur_ = child->collisions();
- end_ = cur_ + child->collision_count();
- }
- return true;
- }
- --depth_;
- }
- return false;
- }
-
- void ensure_valid_()
- {
- while (cur_ == end_) {
- while (step_down())
- if (cur_ != end_)
- return;
- if (!step_right()) {
- // end of sequence
- assert(depth_ == 0);
- cur_ = end_ = nullptr;
- return;
- }
- }
- }
-
- bool equal(const champ_iterator& other) const { return cur_ == other.cur_; }
-
- const T& dereference() const { return *cur_; }
-};
-
-} // namespace hamts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/hamts/node.hpp b/src/third_party/immer/dist/immer/detail/hamts/node.hpp
deleted file mode 100644
index 6cee4e1bd72..00000000000
--- a/src/third_party/immer/dist/immer/detail/hamts/node.hpp
+++ /dev/null
@@ -1,1137 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/combine_standard_layout.hpp>
-#include <immer/detail/hamts/bits.hpp>
-#include <immer/detail/util.hpp>
-
-#include <cassert>
-#include <cstddef>
-
-namespace immer {
-namespace detail {
-namespace hamts {
-
-template <typename T,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- bits_t B>
-struct node
-{
- using node_t = node;
-
- using memory = MemoryPolicy;
- using heap_policy = typename memory::heap;
- using heap = typename heap_policy::type;
- using transience = typename memory::transience_t;
- using refs_t = typename memory::refcount;
- using ownee_t = typename transience::ownee;
- using edit_t = typename transience::edit;
- using value_t = T;
- using bitmap_t = typename get_bitmap_type<B>::type;
-
- enum class kind_t
- {
- collision,
- inner
- };
-
- struct collision_t
- {
- count_t count;
- aligned_storage_for<T> buffer;
- };
-
- struct values_data_t
- {
- aligned_storage_for<T> buffer;
- };
-
- using values_t = combine_standard_layout_t<values_data_t, refs_t, ownee_t>;
-
- struct inner_t
- {
- bitmap_t nodemap;
- bitmap_t datamap;
- values_t* values;
- aligned_storage_for<node_t*> buffer;
- };
-
- union data_t
- {
- inner_t inner;
- collision_t collision;
- };
-
- struct impl_data_t
- {
-#if IMMER_TAGGED_NODE
- kind_t kind;
-#endif
- data_t data;
- };
-
- using impl_t = combine_standard_layout_t<impl_data_t, refs_t, ownee_t>;
-
- impl_t impl;
-
- constexpr static std::size_t sizeof_values_n(count_t count)
- {
- return std::max(sizeof(values_t),
- immer_offsetof(values_t, d.buffer) +
- sizeof(values_data_t::buffer) * count);
- }
-
- constexpr static std::size_t sizeof_collision_n(count_t count)
- {
- return immer_offsetof(impl_t, d.data.collision.buffer) +
- sizeof(collision_t::buffer) * count;
- }
-
- constexpr static std::size_t sizeof_inner_n(count_t count)
- {
- return immer_offsetof(impl_t, d.data.inner.buffer) +
- sizeof(inner_t::buffer) * count;
- }
-
-#if IMMER_TAGGED_NODE
- kind_t kind() const { return impl.d.kind; }
-#endif
-
- auto values()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- assert(impl.d.data.inner.values);
- return (T*) &impl.d.data.inner.values->d.buffer;
- }
-
- auto values() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- assert(impl.d.data.inner.values);
- return (const T*) &impl.d.data.inner.values->d.buffer;
- }
-
- auto children()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return (node_t**) &impl.d.data.inner.buffer;
- }
-
- auto children() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return (const node_t* const*) &impl.d.data.inner.buffer;
- }
-
- auto datamap() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return impl.d.data.inner.datamap;
- }
-
- auto nodemap() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return impl.d.data.inner.nodemap;
- }
-
- auto data_count() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return popcount(datamap());
- }
-
- auto data_count(bitmap_t bit) const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return popcount(static_cast<bitmap_t>(datamap() & (bit - 1)));
- }
-
- auto children_count() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return popcount(nodemap());
- }
-
- auto children_count(bitmap_t bit) const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return popcount(static_cast<bitmap_t>(nodemap() & (bit - 1)));
- }
-
- auto collision_count() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
- return impl.d.data.collision.count;
- }
-
- T* collisions()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
- return (T*) &impl.d.data.collision.buffer;
- }
-
- const T* collisions() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::collision);
- return (const T*) &impl.d.data.collision.buffer;
- }
-
- static refs_t& refs(const values_t* x)
- {
- return auto_const_cast(get<refs_t>(*x));
- }
- static const ownee_t& ownee(const values_t* x) { return get<ownee_t>(*x); }
- static ownee_t& ownee(values_t* x) { return get<ownee_t>(*x); }
- static bool can_mutate(values_t* x, edit_t e)
- {
- return refs(x).unique() || ownee(x).can_mutate(e);
- }
-
- static refs_t& refs(const node_t* x)
- {
- return auto_const_cast(get<refs_t>(x->impl));
- }
- static const ownee_t& ownee(const node_t* x)
- {
- return get<ownee_t>(x->impl);
- }
- static ownee_t& ownee(node_t* x) { return get<ownee_t>(x->impl); }
-
- bool can_mutate(edit_t e) const
- {
- return refs(this).unique() || ownee(this).can_mutate(e);
- }
- bool can_mutate_values(edit_t e) const
- {
- return can_mutate(impl.d.data.inner.values, e);
- }
-
- static node_t* make_inner_n(count_t n)
- {
- assert(n <= branches<B>);
- auto m = heap::allocate(sizeof_inner_n(n));
- auto p = new (m) node_t;
- assert(p == (node_t*) m);
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- p->impl.d.data.inner.nodemap = 0;
- p->impl.d.data.inner.datamap = 0;
- p->impl.d.data.inner.values = nullptr;
- return p;
- }
-
- static node_t* make_inner_n(count_t n, values_t* values)
- {
- auto p = make_inner_n(n);
- if (values) {
- p->impl.d.data.inner.values = values;
- refs(values).inc();
- }
- return p;
- }
-
- static node_t* make_inner_n(count_t n, count_t nv)
- {
- assert(nv <= branches<B>);
- auto p = make_inner_n(n);
- if (nv) {
- IMMER_TRY {
- p->impl.d.data.inner.values =
- new (heap::allocate(sizeof_values_n(nv))) values_t{};
- }
- IMMER_CATCH (...) {
- deallocate_inner(p, n);
- IMMER_RETHROW;
- }
- }
- return p;
- }
-
- static node_t* make_inner_n(count_t n, count_t idx, node_t* child)
- {
- assert(n >= 1);
- auto p = make_inner_n(n);
- p->impl.d.data.inner.nodemap = bitmap_t{1u} << idx;
- p->children()[0] = child;
- return p;
- }
-
- static node_t* make_inner_n(count_t n, bitmap_t bitmap, T x)
- {
- auto p = make_inner_n(n, 1);
- p->impl.d.data.inner.datamap = bitmap;
- IMMER_TRY {
- new (p->values()) T{std::move(x)};
- }
- IMMER_CATCH (...) {
- deallocate_inner(p, n, 1);
- IMMER_RETHROW;
- }
- return p;
- }
-
- static node_t*
- make_inner_n(count_t n, count_t idx1, T x1, count_t idx2, T x2)
- {
- assert(idx1 != idx2);
- auto p = make_inner_n(n, 2);
- p->impl.d.data.inner.datamap =
- (bitmap_t{1u} << idx1) | (bitmap_t{1u} << idx2);
- auto assign = [&](auto&& x1, auto&& x2) {
- auto vp = p->values();
- IMMER_TRY {
- new (vp) T{std::move(x1)};
- IMMER_TRY {
- new (vp + 1) T{std::move(x2)};
- }
- IMMER_CATCH (...) {
- vp->~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(p, n, 2);
- IMMER_RETHROW;
- }
- };
- if (idx1 < idx2)
- assign(x1, x2);
- else
- assign(x2, x1);
- return p;
- }
-
- static node_t* make_collision_n(count_t n)
- {
- auto m = heap::allocate(sizeof_collision_n(n));
- auto p = new (m) node_t;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::collision;
-#endif
- p->impl.d.data.collision.count = n;
- return p;
- }
-
- static node_t* make_collision(T v1, T v2)
- {
- auto m = heap::allocate(sizeof_collision_n(2));
- auto p = new (m) node_t;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::collision;
-#endif
- p->impl.d.data.collision.count = 2;
- auto cols = p->collisions();
- IMMER_TRY {
- new (cols) T{std::move(v1)};
- IMMER_TRY {
- new (cols + 1) T{std::move(v2)};
- }
- IMMER_CATCH (...) {
- cols->~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(p, 2);
- IMMER_RETHROW;
- }
- return p;
- }
-
- T* ensure_mutable_values(edit_t e)
- {
- assert(can_mutate(e));
- auto old = impl.d.data.inner.values;
- if (node_t::can_mutate(old, e))
- return values();
- else {
- auto nv = data_count();
- auto nxt = new (heap::allocate(sizeof_values_n(nv))) values_t{};
- auto dst = (T*) &nxt->d.buffer;
- auto src = values();
- ownee(nxt) = e;
- IMMER_TRY {
- detail::uninitialized_copy(src, src + nv, dst);
- }
- IMMER_CATCH (...) {
- deallocate_values(nxt, nv);
- IMMER_RETHROW;
- }
- impl.d.data.inner.values = nxt;
- if (refs(old).dec())
- delete_values(old, nv);
- return dst;
- }
- }
-
- static node_t* copy_collision_insert(node_t* src, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
- auto n = src->collision_count();
- auto dst = make_collision_n(n + 1);
- auto srcp = src->collisions();
- auto dstp = dst->collisions();
- IMMER_TRY {
- new (dstp) T{std::move(v)};
- IMMER_TRY {
- detail::uninitialized_copy(srcp, srcp + n, dstp + 1);
- }
- IMMER_CATCH (...) {
- dstp->~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(dst, n + 1);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* move_collision_insert(node_t* src, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
- auto n = src->collision_count();
- auto dst = make_collision_n(n + 1);
- auto srcp = src->collisions();
- auto dstp = dst->collisions();
- IMMER_TRY {
- new (dstp) T{std::move(v)};
- IMMER_TRY {
- detail::uninitialized_move(srcp, srcp + n, dstp + 1);
- }
- IMMER_CATCH (...) {
- dstp->~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(dst, n + 1);
- IMMER_RETHROW;
- }
- delete_collision(src);
- return dst;
- }
-
- static node_t* copy_collision_remove(node_t* src, T* v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
- assert(src->collision_count() > 1);
- auto n = src->collision_count();
- auto dst = make_collision_n(n - 1);
- auto srcp = src->collisions();
- auto dstp = dst->collisions();
- IMMER_TRY {
- dstp = detail::uninitialized_copy(srcp, v, dstp);
- IMMER_TRY {
- detail::uninitialized_copy(v + 1, srcp + n, dstp);
- }
- IMMER_CATCH (...) {
- detail::destroy(dst->collisions(), dstp);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(dst, n - 1);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* move_collision_remove(node_t* src, T* v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
- assert(src->collision_count() > 1);
- auto n = src->collision_count();
- auto dst = make_collision_n(n - 1);
- auto srcp = src->collisions();
- auto dstp = dst->collisions();
- IMMER_TRY {
- dstp = detail::uninitialized_move(srcp, v, dstp);
- IMMER_TRY {
- detail::uninitialized_move(v + 1, srcp + n, dstp);
- }
- IMMER_CATCH (...) {
- detail::destroy(dst->collisions(), dstp);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(dst, n - 1);
- IMMER_RETHROW;
- }
- delete_collision(src);
- return dst;
- }
-
- static node_t* copy_collision_replace(node_t* src, T* pos, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::collision);
- auto n = src->collision_count();
- auto dst = make_collision_n(n);
- auto srcp = src->collisions();
- auto dstp = dst->collisions();
- assert(pos >= srcp && pos < srcp + n);
- IMMER_TRY {
- new (dstp) T{std::move(v)};
- IMMER_TRY {
- dstp = detail::uninitialized_copy(srcp, pos, dstp + 1);
- IMMER_TRY {
- detail::uninitialized_copy(pos + 1, srcp + n, dstp);
- }
- IMMER_CATCH (...) {
- detail::destroy(dst->collisions(), dstp);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- dst->collisions()->~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_collision(dst, n);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t*
- copy_inner_replace(node_t* src, count_t offset, node_t* child)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto n = src->children_count();
- auto dst = make_inner_n(n, src->impl.d.data.inner.values);
- auto srcp = src->children();
- auto dstp = dst->children();
- dst->impl.d.data.inner.datamap = src->datamap();
- dst->impl.d.data.inner.nodemap = src->nodemap();
- std::copy(srcp, srcp + n, dstp);
- inc_nodes(srcp, offset);
- inc_nodes(srcp + offset + 1, n - offset - 1);
- dstp[offset] = child;
- return dst;
- }
-
- static node_t* owned(node_t* n, edit_t e)
- {
- ownee(n) = e;
- return n;
- }
-
- static node_t* owned_values(node_t* n, edit_t e)
- {
- ownee(n) = e;
- ownee(n->impl.d.data.inner.values) = e;
- return n;
- }
-
- static node_t* owned_values_safe(node_t* n, edit_t e)
- {
- ownee(n) = e;
- if (n->impl.d.data.inner.values)
- ownee(n->impl.d.data.inner.values) = e;
- return n;
- }
-
- static node_t* copy_inner_replace_value(node_t* src, count_t offset, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(offset < src->data_count());
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n, nv);
- dst->impl.d.data.inner.datamap = src->datamap();
- dst->impl.d.data.inner.nodemap = src->nodemap();
- IMMER_TRY {
- detail::uninitialized_copy(
- src->values(), src->values() + nv, dst->values());
- IMMER_TRY {
- dst->values()[offset] = std::move(v);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), nv);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv);
- IMMER_RETHROW;
- }
- inc_nodes(src->children(), n);
- std::copy(src->children(), src->children() + n, dst->children());
- return dst;
- }
-
- static node_t* copy_inner_replace_merged(node_t* src,
- bitmap_t bit,
- count_t voffset,
- node_t* node)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->nodemap() & bit));
- assert(src->datamap() & bit);
- assert(voffset == src->data_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n + 1, nv - 1);
- auto noffset = src->children_count(bit);
- dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
- dst->impl.d.data.inner.nodemap = src->nodemap() | bit;
- if (nv > 1) {
- IMMER_TRY {
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- detail::uninitialized_copy(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n + 1, nv - 1);
- IMMER_RETHROW;
- }
- }
- inc_nodes(src->children(), n);
- std::copy(src->children(), src->children() + noffset, dst->children());
- std::copy(src->children() + noffset,
- src->children() + n,
- dst->children() + noffset + 1);
- dst->children()[noffset] = node;
- return dst;
- }
-
- static node_t* move_inner_replace_merged(
- edit_t e, node_t* src, bitmap_t bit, count_t voffset, node_t* node)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->nodemap() & bit));
- assert(src->datamap() & bit);
- assert(voffset == src->data_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n + 1, nv - 1);
- auto noffset = src->children_count(bit);
- dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
- dst->impl.d.data.inner.nodemap = src->nodemap() | bit;
- if (nv > 1) {
- auto mutate_values = can_mutate(src->impl.d.data.inner.values, e);
- IMMER_TRY {
- if (mutate_values)
- detail::uninitialized_move(
- src->values(), src->values() + voffset, dst->values());
- else
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- if (mutate_values)
- detail::uninitialized_move(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- else
- detail::uninitialized_copy(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n + 1, nv - 1);
- IMMER_RETHROW;
- }
- }
- // inc_nodes(src->children(), n);
- std::copy(src->children(), src->children() + noffset, dst->children());
- std::copy(src->children() + noffset,
- src->children() + n,
- dst->children() + noffset + 1);
- dst->children()[noffset] = node;
- delete_inner(src);
- return dst;
- }
-
- static node_t* copy_inner_replace_inline(node_t* src,
- bitmap_t bit,
- count_t noffset,
- T value)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->datamap() & bit));
- assert(src->nodemap() & bit);
- assert(noffset == src->children_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n - 1, nv + 1);
- auto voffset = src->data_count(bit);
- dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit;
- dst->impl.d.data.inner.datamap = src->datamap() | bit;
- IMMER_TRY {
- if (nv)
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- new (dst->values() + voffset) T{std::move(value)};
- IMMER_TRY {
- if (nv)
- detail::uninitialized_copy(src->values() + voffset,
- src->values() + nv,
- dst->values() + voffset + 1);
- }
- IMMER_CATCH (...) {
- dst->values()[voffset].~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n - 1, nv + 1);
- IMMER_RETHROW;
- }
- inc_nodes(src->children(), noffset);
- inc_nodes(src->children() + noffset + 1, n - noffset - 1);
- std::copy(src->children(), src->children() + noffset, dst->children());
- std::copy(src->children() + noffset + 1,
- src->children() + n,
- dst->children() + noffset);
- return dst;
- }
-
- static node_t* move_inner_replace_inline(
- edit_t e, node_t* src, bitmap_t bit, count_t noffset, T value)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->datamap() & bit));
- assert(src->nodemap() & bit);
- assert(noffset == src->children_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n - 1, nv + 1);
- auto voffset = src->data_count(bit);
- dst->impl.d.data.inner.nodemap = src->nodemap() & ~bit;
- dst->impl.d.data.inner.datamap = src->datamap() | bit;
- IMMER_TRY {
- auto mutate_values =
- nv && can_mutate(src->impl.d.data.inner.values, e);
- if (nv) {
- if (mutate_values)
- detail::uninitialized_move(
- src->values(), src->values() + voffset, dst->values());
- else
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- }
- IMMER_TRY {
- new (dst->values() + voffset) T{std::move(value)};
- IMMER_TRY {
- if (nv) {
- if (mutate_values)
- detail::uninitialized_move(src->values() + voffset,
- src->values() + nv,
- dst->values() + voffset +
- 1);
- else
- detail::uninitialized_copy(src->values() + voffset,
- src->values() + nv,
- dst->values() + voffset +
- 1);
- }
- }
- IMMER_CATCH (...) {
- dst->values()[voffset].~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n - 1, nv + 1);
- IMMER_RETHROW;
- }
- std::copy(src->children(), src->children() + noffset, dst->children());
- std::copy(src->children() + noffset + 1,
- src->children() + n,
- dst->children() + noffset);
- delete_inner(src);
- return dst;
- }
-
- static node_t*
- copy_inner_remove_value(node_t* src, bitmap_t bit, count_t voffset)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->nodemap() & bit));
- assert(src->datamap() & bit);
- assert(voffset == src->data_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n, nv - 1);
- dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
- dst->impl.d.data.inner.nodemap = src->nodemap();
- if (nv > 1) {
- IMMER_TRY {
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- detail::uninitialized_copy(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv - 1);
- IMMER_RETHROW;
- }
- }
- inc_nodes(src->children(), n);
- std::copy(src->children(), src->children() + n, dst->children());
- return dst;
- }
-
- static node_t* move_inner_remove_value(edit_t e,
- node_t* src,
- bitmap_t bit,
- count_t voffset)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- assert(!(src->nodemap() & bit));
- assert(src->datamap() & bit);
- assert(voffset == src->data_count(bit));
- auto n = src->children_count();
- auto nv = src->data_count();
- auto dst = make_inner_n(n, nv - 1);
- dst->impl.d.data.inner.datamap = src->datamap() & ~bit;
- dst->impl.d.data.inner.nodemap = src->nodemap();
- if (nv > 1) {
- auto mutate_values = can_mutate(src->impl.d.data.inner.values, e);
- if (mutate_values) {
- IMMER_TRY {
- detail::uninitialized_move(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- detail::uninitialized_move(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv - 1);
- IMMER_RETHROW;
- }
- } else {
- IMMER_TRY {
- detail::uninitialized_copy(
- src->values(), src->values() + voffset, dst->values());
- IMMER_TRY {
- detail::uninitialized_copy(src->values() + voffset + 1,
- src->values() + nv,
- dst->values() + voffset);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), voffset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv - 1);
- IMMER_RETHROW;
- }
- }
- }
- std::copy(src->children(), src->children() + n, dst->children());
- delete_inner(src);
- return dst;
- }
-
- static node_t* copy_inner_insert_value(node_t* src, bitmap_t bit, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto n = src->children_count();
- auto nv = src->data_count();
- auto offset = src->data_count(bit);
- auto dst = make_inner_n(n, nv + 1);
- dst->impl.d.data.inner.datamap = src->datamap() | bit;
- dst->impl.d.data.inner.nodemap = src->nodemap();
- IMMER_TRY {
- if (nv)
- detail::uninitialized_copy(
- src->values(), src->values() + offset, dst->values());
- IMMER_TRY {
- new (dst->values() + offset) T{std::move(v)};
- IMMER_TRY {
- if (nv)
- detail::uninitialized_copy(src->values() + offset,
- src->values() + nv,
- dst->values() + offset + 1);
- }
- IMMER_CATCH (...) {
- dst->values()[offset].~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), offset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv + 1);
- IMMER_RETHROW;
- }
- inc_nodes(src->children(), n);
- std::copy(src->children(), src->children() + n, dst->children());
- return dst;
- }
-
- static node_t*
- move_inner_insert_value(edit_t e, node_t* src, bitmap_t bit, T v)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto n = src->children_count();
- auto nv = src->data_count();
- auto offset = src->data_count(bit);
- auto dst = make_inner_n(n, nv + 1);
- dst->impl.d.data.inner.datamap = src->datamap() | bit;
- dst->impl.d.data.inner.nodemap = src->nodemap();
- IMMER_TRY {
- auto mutate_values =
- nv && can_mutate(src->impl.d.data.inner.values, e);
- if (nv) {
- if (mutate_values)
- detail::uninitialized_move(
- src->values(), src->values() + offset, dst->values());
- else
- detail::uninitialized_copy(
- src->values(), src->values() + offset, dst->values());
- }
- IMMER_TRY {
- new (dst->values() + offset) T{std::move(v)};
- IMMER_TRY {
- if (nv) {
- if (mutate_values)
- detail::uninitialized_move(src->values() + offset,
- src->values() + nv,
- dst->values() + offset +
- 1);
- else
- detail::uninitialized_copy(src->values() + offset,
- src->values() + nv,
- dst->values() + offset +
- 1);
- }
- }
- IMMER_CATCH (...) {
- dst->values()[offset].~T();
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->values(), offset);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- deallocate_inner(dst, n, nv + 1);
- IMMER_RETHROW;
- }
- std::copy(src->children(), src->children() + n, dst->children());
- delete_inner(src);
- return dst;
- }
-
- static node_t*
- make_merged(shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
- {
- if (shift < max_shift<B>) {
- auto idx1 = hash1 & (mask<B> << shift);
- auto idx2 = hash2 & (mask<B> << shift);
- if (idx1 == idx2) {
- auto merged = make_merged(
- shift + B, std::move(v1), hash1, std::move(v2), hash2);
- IMMER_TRY {
- return make_inner_n(
- 1, static_cast<count_t>(idx1 >> shift), merged);
- }
- IMMER_CATCH (...) {
- delete_deep_shift(merged, shift + B);
- IMMER_RETHROW;
- }
- } else {
- return make_inner_n(0,
- static_cast<count_t>(idx1 >> shift),
- std::move(v1),
- static_cast<count_t>(idx2 >> shift),
- std::move(v2));
- }
- } else {
- return make_collision(std::move(v1), std::move(v2));
- }
- }
-
- static node_t* make_merged_e(
- edit_t e, shift_t shift, T v1, hash_t hash1, T v2, hash_t hash2)
- {
- if (shift < max_shift<B>) {
- auto idx1 = hash1 & (mask<B> << shift);
- auto idx2 = hash2 & (mask<B> << shift);
- if (idx1 == idx2) {
- auto merged = make_merged_e(
- e, shift + B, std::move(v1), hash1, std::move(v2), hash2);
- IMMER_TRY {
- return owned(
- make_inner_n(
- 1, static_cast<count_t>(idx1 >> shift), merged),
- e);
- }
- IMMER_CATCH (...) {
- delete_deep_shift(merged, shift + B);
- IMMER_RETHROW;
- }
- } else {
- auto r = make_inner_n(0,
- static_cast<count_t>(idx1 >> shift),
- std::move(v1),
- static_cast<count_t>(idx2 >> shift),
- std::move(v2));
- return owned_values(r, e);
- }
- } else {
- return owned(make_collision(std::move(v1), std::move(v2)), e);
- }
- }
-
- node_t* inc()
- {
- refs(this).inc();
- return this;
- }
-
- const node_t* inc() const
- {
- refs(this).inc();
- return this;
- }
-
- bool dec() const { return refs(this).dec(); }
-
- static void inc_nodes(node_t** p, count_t n)
- {
- for (auto i = p, e = i + n; i != e; ++i)
- refs(*i).inc();
- }
-
- static void delete_values(values_t* p, count_t n)
- {
- assert(p);
- detail::destroy_n((T*) &p->d.buffer, n);
- deallocate_values(p, n);
- }
-
- static void delete_inner(node_t* p)
- {
- assert(p);
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
- auto vp = p->impl.d.data.inner.values;
- if (vp && refs(vp).dec())
- delete_values(vp, p->data_count());
- deallocate_inner(p, p->children_count());
- }
-
- static void delete_collision(node_t* p)
- {
- assert(p);
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::collision);
- auto n = p->collision_count();
- detail::destroy_n(p->collisions(), n);
- deallocate_collision(p, n);
- }
-
- static void delete_deep(node_t* p, shift_t s)
- {
- if (s == max_depth<B>)
- delete_collision(p);
- else {
- auto fst = p->children();
- auto lst = fst + p->children_count();
- for (; fst != lst; ++fst)
- if ((*fst)->dec())
- delete_deep(*fst, s + 1);
- delete_inner(p);
- }
- }
-
- static void delete_deep_shift(node_t* p, shift_t s)
- {
- if (s == max_shift<B>)
- delete_collision(p);
- else {
- auto fst = p->children();
- auto lst = fst + p->children_count();
- for (; fst != lst; ++fst)
- if ((*fst)->dec())
- delete_deep_shift(*fst, s + B);
- delete_inner(p);
- }
- }
-
- static void deallocate_values(values_t* p, count_t n)
- {
- heap::deallocate(node_t::sizeof_values_n(n), p);
- }
-
- static void deallocate_collision(node_t* p, count_t n)
- {
- heap::deallocate(node_t::sizeof_collision_n(n), p);
- }
-
- static void deallocate_inner(node_t* p, count_t n)
- {
- heap::deallocate(node_t::sizeof_inner_n(n), p);
- }
-
- static void deallocate_inner(node_t* p, count_t n, count_t nv)
- {
- assert(nv);
- heap::deallocate(node_t::sizeof_values_n(nv),
- p->impl.d.data.inner.values);
- heap::deallocate(node_t::sizeof_inner_n(n), p);
- }
-};
-
-} // namespace hamts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/iterator_facade.hpp b/src/third_party/immer/dist/immer/detail/iterator_facade.hpp
deleted file mode 100644
index 359f3d912c0..00000000000
--- a/src/third_party/immer/dist/immer/detail/iterator_facade.hpp
+++ /dev/null
@@ -1,212 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstddef>
-#include <iterator>
-#include <type_traits>
-
-namespace immer {
-namespace detail {
-
-struct iterator_core_access
-{
- template <typename T>
- static decltype(auto) dereference(T&& x)
- {
- return x.dereference();
- }
-
- template <typename T>
- static decltype(auto) increment(T&& x)
- {
- return x.increment();
- }
-
- template <typename T>
- static decltype(auto) decrement(T&& x)
- {
- return x.decrement();
- }
-
- template <typename T1, typename T2>
- static decltype(auto) equal(T1&& x1, T2&& x2)
- {
- return x1.equal(x2);
- }
-
- template <typename T, typename D>
- static decltype(auto) advance(T&& x, D d)
- {
- return x.advance(d);
- }
-
- template <typename T1, typename T2>
- static decltype(auto) distance_to(T1&& x1, T2&& x2)
- {
- return x1.distance_to(x2);
- }
-};
-
-/*!
- * Minimalistic reimplementation of boost::iterator_facade
- */
-template <typename DerivedT,
- typename IteratorCategoryT,
- typename T,
- typename ReferenceT = T&,
- typename DifferenceTypeT = std::ptrdiff_t,
- typename PointerT = T*>
-class iterator_facade
-{
-public:
- using iterator_category = IteratorCategoryT;
- using value_type = T;
- using difference_type = DifferenceTypeT;
- using pointer = PointerT;
- using reference = ReferenceT;
-
-protected:
- using access_t = iterator_core_access;
-
- constexpr static auto is_random_access =
- std::is_base_of<std::random_access_iterator_tag,
- IteratorCategoryT>::value;
- constexpr static auto is_bidirectional =
- std::is_base_of<std::bidirectional_iterator_tag,
- IteratorCategoryT>::value;
-
- class reference_proxy
- {
- friend iterator_facade;
- DerivedT iter_;
-
- reference_proxy(DerivedT iter)
- : iter_{std::move(iter)}
- {}
-
- public:
- operator ReferenceT() const { return *iter_; }
- };
-
- const DerivedT& derived() const
- {
- static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
- "must pass a derived thing");
- return *static_cast<const DerivedT*>(this);
- }
- DerivedT& derived()
- {
- static_assert(std::is_base_of<iterator_facade, DerivedT>::value,
- "must pass a derived thing");
- return *static_cast<DerivedT*>(this);
- }
-
-public:
- ReferenceT operator*() const { return access_t::dereference(derived()); }
- PointerT operator->() const { return &access_t::dereference(derived()); }
- reference_proxy operator[](DifferenceTypeT n) const
- {
- static_assert(is_random_access, "");
- return derived() + n;
- }
-
- friend bool operator==(const DerivedT& a, const DerivedT& b)
- {
- return access_t::equal(a, b);
- }
- friend bool operator!=(const DerivedT& a, const DerivedT& b)
- {
- return !access_t::equal(a, b);
- }
-
- DerivedT& operator++()
- {
- access_t::increment(derived());
- return derived();
- }
- DerivedT operator++(int)
- {
- auto tmp = derived();
- access_t::increment(derived());
- return tmp;
- }
-
- DerivedT& operator--()
- {
- static_assert(is_bidirectional || is_random_access, "");
- access_t::decrement(derived());
- return derived();
- }
- DerivedT operator--(int)
- {
- static_assert(is_bidirectional || is_random_access, "");
- auto tmp = derived();
- access_t::decrement(derived());
- return tmp;
- }
-
- DerivedT& operator+=(DifferenceTypeT n)
- {
- access_t::advance(derived(), n);
- return derived();
- }
- DerivedT& operator-=(DifferenceTypeT n)
- {
- access_t::advance(derived(), -n);
- return derived();
- }
-
- DerivedT operator+(DifferenceTypeT n) const
- {
- static_assert(is_random_access, "");
- auto tmp = derived();
- return tmp += n;
- }
- friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i)
- {
- static_assert(is_random_access, "");
- return i + n;
- }
- DerivedT operator-(DifferenceTypeT n) const
- {
- static_assert(is_random_access, "");
- auto tmp = derived();
- return tmp -= n;
- }
- friend DifferenceTypeT operator-(const DerivedT& a, const DerivedT& b)
- {
- static_assert(is_random_access, "");
- return access_t::distance_to(b, a);
- }
-
- friend bool operator<(const DerivedT& a, const DerivedT& b)
- {
- static_assert(is_random_access, "");
- return access_t::distance_to(a, b) > 0;
- }
- friend bool operator<=(const DerivedT& a, const DerivedT& b)
- {
- static_assert(is_random_access, "");
- return access_t::distance_to(a, b) >= 0;
- }
- friend bool operator>(const DerivedT& a, const DerivedT& b)
- {
- static_assert(is_random_access, "");
- return access_t::distance_to(a, b) < 0;
- }
- friend bool operator>=(const DerivedT& a, const DerivedT& b)
- {
- static_assert(is_random_access, "");
- return access_t::distance_to(a, b) <= 0;
- }
-};
-
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/bits.hpp b/src/third_party/immer/dist/immer/detail/rbts/bits.hpp
deleted file mode 100644
index f86b44fb016..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/bits.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstddef>
-#include <cstdint>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-using bits_t = std::uint32_t;
-using shift_t = std::uint32_t;
-using count_t = std::uint32_t;
-using size_t = std::size_t;
-
-template <bits_t B, typename T = count_t>
-constexpr T branches = T{1} << B;
-
-template <bits_t B, typename T = size_t>
-constexpr T mask = branches<B, T> - 1;
-
-template <bits_t B, bits_t BL>
-constexpr shift_t endshift = shift_t{BL} - shift_t{B};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/node.hpp b/src/third_party/immer/dist/immer/detail/rbts/node.hpp
deleted file mode 100644
index 55a512b03d8..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/node.hpp
+++ /dev/null
@@ -1,1033 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/combine_standard_layout.hpp>
-#include <immer/detail/rbts/bits.hpp>
-#include <immer/detail/util.hpp>
-#include <immer/heap/tags.hpp>
-
-#include <cassert>
-#include <cstddef>
-#include <memory>
-#include <type_traits>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T, typename MemoryPolicy, bits_t B, bits_t BL>
-struct node
-{
- static constexpr auto bits = B;
- static constexpr auto bits_leaf = BL;
-
- using node_t = node;
- using memory = MemoryPolicy;
- using heap_policy = typename memory::heap;
- using transience = typename memory::transience_t;
- using refs_t = typename memory::refcount;
- using ownee_t = typename transience::ownee;
- using edit_t = typename transience::edit;
- using value_t = T;
-
- static constexpr bool embed_relaxed = memory::prefer_fewer_bigger_objects;
-
- enum class kind_t
- {
- leaf,
- inner
- };
-
- struct relaxed_data_t
- {
- count_t count;
- size_t sizes[branches<B>];
- };
-
- using relaxed_data_with_meta_t =
- combine_standard_layout_t<relaxed_data_t, refs_t, ownee_t>;
-
- using relaxed_data_no_meta_t = combine_standard_layout_t<relaxed_data_t>;
-
- using relaxed_t = std::conditional_t<embed_relaxed,
- relaxed_data_no_meta_t,
- relaxed_data_with_meta_t>;
-
- struct leaf_t
- {
- aligned_storage_for<T> buffer;
- };
-
- struct inner_t
- {
- relaxed_t* relaxed;
- aligned_storage_for<node_t*> buffer;
- };
-
- union data_t
- {
- inner_t inner;
- leaf_t leaf;
- };
-
- struct impl_data_t
- {
-#if IMMER_TAGGED_NODE
- kind_t kind;
-#endif
- data_t data;
- };
-
- using impl_t = combine_standard_layout_t<impl_data_t, refs_t, ownee_t>;
-
- impl_t impl;
-
- // assume that we need to keep headroom space in the node when we
- // are doing reference counting, since any node may become
- // transient when it has only one reference
- constexpr static bool keep_headroom = !std::is_empty<refs_t>{};
-
- constexpr static std::size_t sizeof_packed_leaf_n(count_t count)
- {
- return immer_offsetof(impl_t, d.data.leaf.buffer) +
- sizeof(leaf_t::buffer) * count;
- }
-
- constexpr static std::size_t sizeof_packed_inner_n(count_t count)
- {
- return immer_offsetof(impl_t, d.data.inner.buffer) +
- sizeof(inner_t::buffer) * count;
- }
-
- constexpr static std::size_t sizeof_packed_relaxed_n(count_t count)
- {
- return immer_offsetof(relaxed_t, d.sizes) + sizeof(size_t) * count;
- }
-
- constexpr static std::size_t sizeof_packed_inner_r_n(count_t count)
- {
- return embed_relaxed ? sizeof_packed_inner_n(count) +
- sizeof_packed_relaxed_n(count)
- : sizeof_packed_inner_n(count);
- }
-
- constexpr static std::size_t max_sizeof_leaf =
- sizeof_packed_leaf_n(branches<BL>);
-
- constexpr static std::size_t max_sizeof_inner =
- sizeof_packed_inner_n(branches<B>);
-
- constexpr static std::size_t max_sizeof_relaxed =
- sizeof_packed_relaxed_n(branches<B>);
-
- constexpr static std::size_t max_sizeof_inner_r =
- sizeof_packed_inner_r_n(branches<B>);
-
- constexpr static std::size_t sizeof_inner_n(count_t n)
- {
- return keep_headroom ? max_sizeof_inner : sizeof_packed_inner_n(n);
- }
-
- constexpr static std::size_t sizeof_inner_r_n(count_t n)
- {
- return keep_headroom ? max_sizeof_inner_r : sizeof_packed_inner_r_n(n);
- }
-
- constexpr static std::size_t sizeof_relaxed_n(count_t n)
- {
- return keep_headroom ? max_sizeof_relaxed : sizeof_packed_relaxed_n(n);
- }
-
- constexpr static std::size_t sizeof_leaf_n(count_t n)
- {
- return keep_headroom ? max_sizeof_leaf : sizeof_packed_leaf_n(n);
- }
-
- using heap =
- typename heap_policy::template optimized<max_sizeof_inner>::type;
-
-#if IMMER_TAGGED_NODE
- kind_t kind() const { return impl.d.kind; }
-#endif
-
- relaxed_t* relaxed()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return impl.d.data.inner.relaxed;
- }
-
- const relaxed_t* relaxed() const
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return impl.d.data.inner.relaxed;
- }
-
- node_t** inner()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::inner);
- return reinterpret_cast<node_t**>(&impl.d.data.inner.buffer);
- }
-
- T* leaf()
- {
- IMMER_ASSERT_TAGGED(kind() == kind_t::leaf);
- return reinterpret_cast<T*>(&impl.d.data.leaf.buffer);
- }
-
- static refs_t& refs(const relaxed_t* x)
- {
- return auto_const_cast(get<refs_t>(*x));
- }
- static const ownee_t& ownee(const relaxed_t* x) { return get<ownee_t>(*x); }
- static ownee_t& ownee(relaxed_t* x) { return get<ownee_t>(*x); }
-
- static refs_t& refs(const node_t* x)
- {
- return auto_const_cast(get<refs_t>(x->impl));
- }
- static const ownee_t& ownee(const node_t* x)
- {
- return get<ownee_t>(x->impl);
- }
- static ownee_t& ownee(node_t* x) { return get<ownee_t>(x->impl); }
-
- static node_t* make_inner_n_into(void* buffer, std::size_t size, count_t n)
- {
- assert(n <= branches<B>);
- assert(size >= sizeof_inner_n(n));
- auto p = new (buffer) node_t;
- p->impl.d.data.inner.relaxed = nullptr;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- }
- static node_t* make_inner_n(count_t n)
- {
- assert(n <= branches<B>);
- auto m = heap::allocate(sizeof_inner_n(n));
- return make_inner_n_into(m, sizeof_inner_n(n), n);
- }
-
- static node_t* make_inner_e(edit_t e)
- {
- auto m = heap::allocate(max_sizeof_inner);
- auto p = new (m) node_t;
- ownee(p) = e;
- p->impl.d.data.inner.relaxed = nullptr;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n)
- {
- assert(n <= branches<B>);
- auto mp = heap::allocate(sizeof_inner_r_n(n));
- auto mr = static_cast<void*>(nullptr);
- if (embed_relaxed) {
- mr = reinterpret_cast<unsigned char*>(mp) + sizeof_inner_n(n);
- } else {
- IMMER_TRY {
- mr = heap::allocate(sizeof_relaxed_n(n), norefs_tag{});
- }
- IMMER_CATCH (...) {
- heap::deallocate(sizeof_inner_r_n(n), mp);
- IMMER_RETHROW;
- }
- }
- auto p = new (mp) node_t;
- auto r = new (mr) relaxed_t;
- r->d.count = 0;
- p->impl.d.data.inner.relaxed = r;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- }
-
- static node_t* make_inner_sr_n(count_t n, relaxed_t* r)
- {
- return static_if<embed_relaxed, node_t*>(
- [&](auto) { return node_t::make_inner_r_n(n); },
- [&](auto) {
- auto p =
- new (heap::allocate(node_t::sizeof_inner_r_n(n))) node_t;
- assert(r->d.count >= n);
- node_t::refs(r).inc();
- p->impl.d.data.inner.relaxed = r;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- });
- }
-
- static node_t* make_inner_r_e(edit_t e)
- {
- auto mp = heap::allocate(max_sizeof_inner_r);
- auto mr = static_cast<void*>(nullptr);
- if (embed_relaxed) {
- mr = reinterpret_cast<unsigned char*>(mp) + max_sizeof_inner;
- } else {
- IMMER_TRY {
- mr = heap::allocate(max_sizeof_relaxed, norefs_tag{});
- }
- IMMER_CATCH (...) {
- heap::deallocate(max_sizeof_inner_r, mp);
- IMMER_RETHROW;
- }
- }
- auto p = new (mp) node_t;
- auto r = new (mr) relaxed_t;
- ownee(p) = e;
- static_if<!embed_relaxed>([&](auto) { node_t::ownee(r) = e; });
- r->d.count = 0;
- p->impl.d.data.inner.relaxed = r;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- }
-
- static node_t* make_inner_sr_e(edit_t e, relaxed_t* r)
- {
- return static_if<embed_relaxed, node_t*>(
- [&](auto) { return node_t::make_inner_r_e(e); },
- [&](auto) {
- auto p =
- new (heap::allocate(node_t::max_sizeof_inner_r)) node_t;
- node_t::refs(r).inc();
- p->impl.d.data.inner.relaxed = r;
- node_t::ownee(p) = e;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::inner;
-#endif
- return p;
- });
- }
-
- static node_t* make_leaf_n_into(void* buffer, std::size_t size, count_t n)
- {
- assert(n <= branches<BL>);
- assert(size >= sizeof_leaf_n(n));
- auto p = new (buffer) node_t;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::leaf;
-#endif
- return p;
- }
-
- static node_t* make_leaf_n(count_t n)
- {
- assert(n <= branches<BL>);
- auto m = heap::allocate(sizeof_leaf_n(n));
- return make_leaf_n_into(m, sizeof_leaf_n(n), n);
- }
-
- static node_t* make_leaf_e(edit_t e)
- {
- auto p = new (heap::allocate(max_sizeof_leaf)) node_t;
- ownee(p) = e;
-#if IMMER_TAGGED_NODE
- p->impl.d.kind = node_t::kind_t::leaf;
-#endif
- return p;
- }
-
- static node_t* make_inner_n(count_t n, node_t* x)
- {
- assert(n >= 1);
- auto p = make_inner_n(n);
- p->inner()[0] = x;
- return p;
- }
-
- static node_t* make_inner_n(edit_t n, node_t* x)
- {
- assert(n >= 1);
- auto p = make_inner_n(n);
- p->inner()[0] = x;
- return p;
- }
-
- static node_t* make_inner_n(count_t n, node_t* x, node_t* y)
- {
- assert(n >= 2);
- auto p = make_inner_n(n);
- p->inner()[0] = x;
- p->inner()[1] = y;
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n, node_t* x)
- {
- assert(n >= 1);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- r->d.count = 1;
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n, node_t* x, size_t xs)
- {
- assert(n >= 1);
- assert(xs);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- r->d.sizes[0] = xs;
- r->d.count = 1;
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n, node_t* x, node_t* y)
- {
- assert(n >= 2);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- p->inner()[1] = y;
- r->d.count = 2;
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n, node_t* x, size_t xs, node_t* y)
- {
- assert(n >= 2);
- assert(xs);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- p->inner()[1] = y;
- r->d.sizes[0] = xs;
- r->d.count = 2;
- return p;
- }
-
- static node_t*
- make_inner_r_n(count_t n, node_t* x, size_t xs, node_t* y, size_t ys)
- {
- assert(n >= 2);
- assert(xs);
- assert(ys);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- p->inner()[1] = y;
- r->d.sizes[0] = xs;
- r->d.sizes[1] = xs + ys;
- r->d.count = 2;
- return p;
- }
-
- static node_t* make_inner_r_n(count_t n,
- node_t* x,
- size_t xs,
- node_t* y,
- size_t ys,
- node_t* z,
- size_t zs)
- {
- assert(n >= 3);
- assert(xs);
- assert(ys);
- assert(zs);
- auto p = make_inner_r_n(n);
- auto r = p->relaxed();
- p->inner()[0] = x;
- p->inner()[1] = y;
- p->inner()[2] = z;
- r->d.sizes[0] = xs;
- r->d.sizes[1] = xs + ys;
- r->d.sizes[2] = xs + ys + zs;
- r->d.count = 3;
- return p;
- }
-
- template <typename U>
- static node_t* make_leaf_n(count_t n, U&& x)
- {
- assert(n >= 1);
- auto p = make_leaf_n(n);
- IMMER_TRY {
- new (p->leaf()) T{std::forward<U>(x)};
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_leaf_n(n), p);
- IMMER_RETHROW;
- }
- return p;
- }
-
- template <typename U>
- static node_t* make_leaf_e(edit_t e, U&& x)
- {
- auto p = make_leaf_e(e);
- IMMER_TRY {
- new (p->leaf()) T{std::forward<U>(x)};
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::max_sizeof_leaf, p);
- IMMER_RETHROW;
- }
- return p;
- }
-
- static node_t* make_path(shift_t shift, node_t* node)
- {
- IMMER_ASSERT_TAGGED(node->kind() == kind_t::leaf);
- if (shift == endshift<B, BL>)
- return node;
- else {
- auto n = node_t::make_inner_n(1);
- IMMER_TRY {
- n->inner()[0] = make_path(shift - B, node);
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_inner_n(1), n);
- IMMER_RETHROW;
- }
- return n;
- }
- }
-
- static node_t* make_path_e(edit_t e, shift_t shift, node_t* node)
- {
- IMMER_ASSERT_TAGGED(node->kind() == kind_t::leaf);
- if (shift == endshift<B, BL>)
- return node;
- else {
- auto n = node_t::make_inner_e(e);
- IMMER_TRY {
- n->inner()[0] = make_path_e(e, shift - B, node);
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::max_sizeof_inner, n);
- IMMER_RETHROW;
- }
- return n;
- }
- }
-
- static node_t* copy_inner(node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_n(n);
- inc_nodes(src->inner(), n);
- std::copy(src->inner(), src->inner() + n, dst->inner());
- return dst;
- }
-
- static node_t* copy_inner_n(count_t allocn, node_t* src, count_t n)
- {
- assert(allocn >= n);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_n(allocn);
- return do_copy_inner(dst, src, n);
- }
-
- static node_t* copy_inner_e(edit_t e, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_e(e);
- return do_copy_inner(dst, src, n);
- }
-
- static node_t* do_copy_inner(node_t* dst, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto p = src->inner();
- inc_nodes(p, n);
- std::copy(p, p + n, dst->inner());
- return dst;
- }
-
- static node_t* do_copy_inner_replace(
- node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
- {
- IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto p = src->inner();
- inc_nodes(p, offset);
- inc_nodes(p + offset + 1, n - offset - 1);
- std::copy(p, p + n, dst->inner());
- dst->inner()[offset] = child;
- return dst;
- }
-
- static node_t* copy_inner_r(node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_r_n(n);
- return do_copy_inner_r(dst, src, n);
- }
-
- static node_t* copy_inner_r_n(count_t allocn, node_t* src, count_t n)
- {
- assert(allocn >= n);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_r_n(allocn);
- return do_copy_inner_r(dst, src, n);
- }
-
- static node_t* copy_inner_r_e(edit_t e, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_r_e(e);
- return do_copy_inner_r(dst, src, n);
- }
-
- static node_t* copy_inner_sr_e(edit_t e, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto dst = make_inner_sr_e(e, src->relaxed());
- return do_copy_inner_sr(dst, src, n);
- }
-
- static node_t* do_copy_inner_r(node_t* dst, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto src_r = src->relaxed();
- auto dst_r = dst->relaxed();
- inc_nodes(src->inner(), n);
- std::copy(src->inner(), src->inner() + n, dst->inner());
- std::copy(src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
- dst_r->d.count = n;
- return dst;
- }
-
- static node_t* do_copy_inner_replace_r(
- node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
- {
- IMMER_ASSERT_TAGGED(dst->kind() == kind_t::inner);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::inner);
- auto src_r = src->relaxed();
- auto dst_r = dst->relaxed();
- auto p = src->inner();
- inc_nodes(p, offset);
- inc_nodes(p + offset + 1, n - offset - 1);
- std::copy(src->inner(), src->inner() + n, dst->inner());
- std::copy(src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
- dst_r->d.count = n;
- dst->inner()[offset] = child;
- return dst;
- }
-
- static node_t* do_copy_inner_sr(node_t* dst, node_t* src, count_t n)
- {
- if (embed_relaxed)
- return do_copy_inner_r(dst, src, n);
- else {
- inc_nodes(src->inner(), n);
- std::copy(src->inner(), src->inner() + n, dst->inner());
- return dst;
- }
- }
-
- static node_t* do_copy_inner_replace_sr(
- node_t* dst, node_t* src, count_t n, count_t offset, node_t* child)
- {
- if (embed_relaxed)
- return do_copy_inner_replace_r(dst, src, n, offset, child);
- else {
- auto p = src->inner();
- inc_nodes(p, offset);
- inc_nodes(p + offset + 1, n - offset - 1);
- std::copy(p, p + n, dst->inner());
- dst->inner()[offset] = child;
- return dst;
- }
- }
-
- static node_t* copy_leaf(node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
- auto dst = make_leaf_n(n);
- IMMER_TRY {
- detail::uninitialized_copy(
- src->leaf(), src->leaf() + n, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_leaf_n(n), dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* copy_leaf_e(edit_t e, node_t* src, count_t n)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
- auto dst = make_leaf_e(e);
- IMMER_TRY {
- detail::uninitialized_copy(
- src->leaf(), src->leaf() + n, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::max_sizeof_leaf, dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* copy_leaf_n(count_t allocn, node_t* src, count_t n)
- {
- assert(allocn >= n);
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
- auto dst = make_leaf_n(allocn);
- IMMER_TRY {
- detail::uninitialized_copy(
- src->leaf(), src->leaf() + n, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_leaf_n(allocn), dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* copy_leaf(node_t* src1, count_t n1, node_t* src2, count_t n2)
- {
- IMMER_ASSERT_TAGGED(src1->kind() == kind_t::leaf);
- IMMER_ASSERT_TAGGED(src2->kind() == kind_t::leaf);
- auto dst = make_leaf_n(n1 + n2);
- IMMER_TRY {
- detail::uninitialized_copy(
- src1->leaf(), src1->leaf() + n1, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_leaf_n(n1 + n2), dst);
- IMMER_RETHROW;
- }
- IMMER_TRY {
- detail::uninitialized_copy(
- src2->leaf(), src2->leaf() + n2, dst->leaf() + n1);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->leaf(), n1);
- heap::deallocate(node_t::sizeof_leaf_n(n1 + n2), dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t*
- copy_leaf_e(edit_t e, node_t* src1, count_t n1, node_t* src2, count_t n2)
- {
- IMMER_ASSERT_TAGGED(src1->kind() == kind_t::leaf);
- IMMER_ASSERT_TAGGED(src2->kind() == kind_t::leaf);
- auto dst = make_leaf_e(e);
- IMMER_TRY {
- detail::uninitialized_copy(
- src1->leaf(), src1->leaf() + n1, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(max_sizeof_leaf, dst);
- IMMER_RETHROW;
- }
- IMMER_TRY {
- detail::uninitialized_copy(
- src2->leaf(), src2->leaf() + n2, dst->leaf() + n1);
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->leaf(), n1);
- heap::deallocate(max_sizeof_leaf, dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* copy_leaf_e(edit_t e, node_t* src, count_t idx, count_t last)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
- auto dst = make_leaf_e(e);
- IMMER_TRY {
- detail::uninitialized_copy(
- src->leaf() + idx, src->leaf() + last, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(max_sizeof_leaf, dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static node_t* copy_leaf(node_t* src, count_t idx, count_t last)
- {
- IMMER_ASSERT_TAGGED(src->kind() == kind_t::leaf);
- auto dst = make_leaf_n(last - idx);
- IMMER_TRY {
- detail::uninitialized_copy(
- src->leaf() + idx, src->leaf() + last, dst->leaf());
- }
- IMMER_CATCH (...) {
- heap::deallocate(node_t::sizeof_leaf_n(last - idx), dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- template <typename U>
- static node_t* copy_leaf_emplace(node_t* src, count_t n, U&& x)
- {
- auto dst = copy_leaf_n(n + 1, src, n);
- IMMER_TRY {
- new (dst->leaf() + n) T{std::forward<U>(x)};
- }
- IMMER_CATCH (...) {
- detail::destroy_n(dst->leaf(), n);
- heap::deallocate(node_t::sizeof_leaf_n(n + 1), dst);
- IMMER_RETHROW;
- }
- return dst;
- }
-
- static void delete_inner(node_t* p, count_t n)
- {
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
- assert(!p->relaxed());
- heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_inner
- : node_t::sizeof_inner_n(n),
- p);
- }
-
- static void delete_inner_e(node_t* p)
- {
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
- assert(!p->relaxed());
- heap::deallocate(node_t::max_sizeof_inner, p);
- }
-
- static void delete_inner_any(node_t* p, count_t n)
- {
- if (p->relaxed())
- delete_inner_r(p, n);
- else
- delete_inner(p, n);
- }
-
- static void delete_inner_r(node_t* p, count_t n)
- {
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
- auto r = p->relaxed();
- assert(r);
- static_if<!embed_relaxed>([&](auto) {
- if (node_t::refs(r).dec())
- heap::deallocate(node_t::ownee(r).owned()
- ? node_t::max_sizeof_relaxed
- : node_t::sizeof_relaxed_n(n),
- r);
- });
- heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_inner_r
- : node_t::sizeof_inner_r_n(n),
- p);
- }
-
- static void delete_inner_r_e(node_t* p)
- {
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::inner);
- auto r = p->relaxed();
- assert(r);
- static_if<!embed_relaxed>([&](auto) {
- if (node_t::refs(r).dec())
- heap::deallocate(node_t::max_sizeof_relaxed, r);
- });
- heap::deallocate(node_t::max_sizeof_inner_r, p);
- }
-
- static void delete_leaf(node_t* p, count_t n)
- {
- IMMER_ASSERT_TAGGED(p->kind() == kind_t::leaf);
- detail::destroy_n(p->leaf(), n);
- heap::deallocate(ownee(p).owned() ? node_t::max_sizeof_leaf
- : node_t::sizeof_leaf_n(n),
- p);
- }
-
- bool can_mutate(edit_t e) const
- {
- return refs(this).unique() || ownee(this).can_mutate(e);
- }
-
- bool can_relax() const { return !embed_relaxed || relaxed(); }
-
- relaxed_t* ensure_mutable_relaxed(edit_t e)
- {
- auto src_r = relaxed();
- return static_if<embed_relaxed, relaxed_t*>(
- [&](auto) { return src_r; },
- [&](auto) {
- if (node_t::refs(src_r).unique() ||
- node_t::ownee(src_r).can_mutate(e))
- return src_r;
- else {
- auto dst_r = impl.d.data.inner.relaxed =
- new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
- if (src_r) {
- auto n = dst_r->d.count = src_r->d.count;
- std::copy(
- src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
- if (node_t::refs(src_r).dec())
- heap::deallocate(node_t::sizeof_inner_r_n(n),
- src_r);
- }
- node_t::ownee(dst_r) = e;
- return dst_r;
- }
- });
- }
-
- relaxed_t* ensure_mutable_relaxed_e(edit_t e, edit_t ec)
- {
- auto src_r = relaxed();
- return static_if<embed_relaxed, relaxed_t*>(
- [&](auto) { return src_r; },
- [&](auto) {
- if (src_r && (node_t::refs(src_r).unique() ||
- node_t::ownee(src_r).can_mutate(e))) {
- node_t::ownee(src_r) = ec;
- return src_r;
- } else {
- auto dst_r = impl.d.data.inner.relaxed =
- new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
- if (src_r) {
- auto n = dst_r->d.count = src_r->d.count;
- std::copy(
- src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
- if (node_t::refs(src_r).dec())
- heap::deallocate(node_t::sizeof_inner_r_n(n),
- src_r);
- }
- node_t::ownee(dst_r) = ec;
- return dst_r;
- }
- });
- }
-
- relaxed_t* ensure_mutable_relaxed_n(edit_t e, count_t n)
- {
- auto src_r = relaxed();
- return static_if<embed_relaxed, relaxed_t*>(
- [&](auto) { return src_r; },
- [&](auto) {
- if (node_t::refs(src_r).unique() ||
- node_t::ownee(src_r).can_mutate(e))
- return src_r;
- else {
- auto dst_r =
- new (heap::allocate(max_sizeof_relaxed)) relaxed_t;
- if (src_r) {
- std::copy(
- src_r->d.sizes, src_r->d.sizes + n, dst_r->d.sizes);
- if (node_t::refs(src_r).dec())
- heap::deallocate(node_t::sizeof_inner_r_n(n),
- src_r);
- }
- dst_r->d.count = n;
- node_t::ownee(dst_r) = e;
- return impl.d.data.inner.relaxed = dst_r;
- }
- });
- }
-
- node_t* inc()
- {
- refs(this).inc();
- return this;
- }
-
- const node_t* inc() const
- {
- refs(this).inc();
- return this;
- }
-
- bool dec() const { return refs(this).dec(); }
-
- static void inc_nodes(node_t** p, count_t n)
- {
- for (auto i = p, e = i + n; i != e; ++i)
- refs(*i).inc();
- }
-
-#if IMMER_TAGGED_NODE
- shift_t compute_shift()
- {
- if (kind() == kind_t::leaf)
- return endshift<B, BL>;
- else
- return B + inner()[0]->compute_shift();
- }
-#endif
-
- bool check(shift_t shift, size_t size)
- {
-#if IMMER_DEBUG_DEEP_CHECK
- assert(size > 0);
- if (shift == endshift<B, BL>) {
- IMMER_ASSERT_TAGGED(kind() == kind_t::leaf);
- assert(size <= branches<BL>);
- } else if (auto r = relaxed()) {
- auto count = r->d.count;
- assert(count > 0);
- assert(count <= branches<B>);
- if (r->d.sizes[count - 1] != size) {
- IMMER_TRACE_F("check");
- IMMER_TRACE_E(r->d.sizes[count - 1]);
- IMMER_TRACE_E(size);
- }
- assert(r->d.sizes[count - 1] == size);
- for (auto i = 1u; i < count; ++i)
- assert(r->d.sizes[i - 1] < r->d.sizes[i]);
- auto last_size = size_t{};
- for (auto i = 0u; i < count; ++i) {
- assert(inner()[i]->check(shift - B, r->d.sizes[i] - last_size));
- last_size = r->d.sizes[i];
- }
- } else {
- assert(size <= branches<B> << shift);
- auto count =
- (size >> shift) + (size - ((size >> shift) << shift) > 0);
- assert(count <= branches<B>);
- if (count) {
- for (auto i = 1u; i < count - 1; ++i)
- assert(inner()[i]->check(shift - B, 1 << shift));
- assert(inner()[count - 1]->check(
- shift - B, size - ((count - 1) << shift)));
- }
- }
-#endif // IMMER_DEBUG_DEEP_CHECK
- return true;
- }
-};
-
-template <typename T, typename MP, bits_t B>
-constexpr bits_t derive_bits_leaf_aux()
-{
- using node_t = node<T, MP, B, B>;
- constexpr auto sizeof_elem = sizeof(T);
- constexpr auto space =
- node_t::max_sizeof_inner - node_t::sizeof_packed_leaf_n(0);
- constexpr auto full_elems = space / sizeof_elem;
- constexpr auto BL = log2(full_elems);
- return BL;
-}
-
-template <typename T, typename MP, bits_t B>
-constexpr bits_t derive_bits_leaf = derive_bits_leaf_aux<T, MP, B>();
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/operations.hpp b/src/third_party/immer/dist/immer/detail/rbts/operations.hpp
deleted file mode 100644
index d5ff67934bc..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/operations.hpp
+++ /dev/null
@@ -1,2508 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <algorithm>
-#include <memory>
-#include <numeric>
-#include <utility>
-
-#include <immer/config.hpp>
-#include <immer/detail/rbts/position.hpp>
-#include <immer/detail/rbts/visitor.hpp>
-#include <immer/detail/util.hpp>
-#include <immer/heap/tags.hpp>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T>
-struct array_for_visitor : visitor_base<array_for_visitor<T>>
-{
- using this_t = array_for_visitor;
-
- template <typename PosT>
- static T* visit_inner(PosT&& pos, size_t idx)
- {
- return pos.descend(this_t{}, idx);
- }
-
- template <typename PosT>
- static T* visit_leaf(PosT&& pos, size_t)
- {
- return pos.node()->leaf();
- }
-};
-
-template <typename T>
-struct region_for_visitor : visitor_base<region_for_visitor<T>>
-{
- using this_t = region_for_visitor;
- using result_t = std::tuple<T*, size_t, size_t>;
-
- template <typename PosT>
- static result_t visit_inner(PosT&& pos, size_t idx)
- {
- return pos.towards(this_t{}, idx);
- }
-
- template <typename PosT>
- static result_t visit_leaf(PosT&& pos, size_t idx)
- {
- return std::make_tuple(pos.node()->leaf(), pos.index(idx), pos.count());
- }
-};
-
-template <typename T>
-struct get_visitor : visitor_base<get_visitor<T>>
-{
- using this_t = get_visitor;
-
- template <typename PosT>
- static const T& visit_inner(PosT&& pos, size_t idx)
- {
- return pos.descend(this_t{}, idx);
- }
-
- template <typename PosT>
- static const T& visit_leaf(PosT&& pos, size_t idx)
- {
- return pos.node()->leaf()[pos.index(idx)];
- }
-};
-
-struct for_each_chunk_visitor : visitor_base<for_each_chunk_visitor>
-{
- using this_t = for_each_chunk_visitor;
-
- template <typename Pos, typename Fn>
- static void visit_inner(Pos&& pos, Fn&& fn)
- {
- pos.each(this_t{}, fn);
- }
-
- template <typename Pos, typename Fn>
- static void visit_leaf(Pos&& pos, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- fn(as_const(data), as_const(data) + pos.count());
- }
-};
-
-struct for_each_chunk_p_visitor : visitor_base<for_each_chunk_p_visitor>
-{
- using this_t = for_each_chunk_p_visitor;
-
- template <typename Pos, typename Fn>
- static bool visit_inner(Pos&& pos, Fn&& fn)
- {
- return pos.each_pred(this_t{}, fn);
- }
-
- template <typename Pos, typename Fn>
- static bool visit_leaf(Pos&& pos, Fn&& fn)
- {
- auto data = as_const(pos.node()->leaf());
- return fn(data, data + pos.count());
- }
-};
-
-struct for_each_chunk_left_visitor : visitor_base<for_each_chunk_left_visitor>
-{
- using this_t = for_each_chunk_left_visitor;
-
- template <typename Pos, typename Fn>
- static void visit_inner(Pos&& pos, size_t last, Fn&& fn)
- {
- auto l = pos.index(last);
- pos.each_left(for_each_chunk_visitor{}, l, fn);
- pos.towards_oh(this_t{}, last, l, fn);
- }
-
- template <typename Pos, typename Fn>
- static void visit_leaf(Pos&& pos, size_t last, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- auto l = pos.index(last);
- fn(data, data + l + 1);
- }
-};
-
-struct for_each_chunk_right_visitor : visitor_base<for_each_chunk_right_visitor>
-{
- using this_t = for_each_chunk_right_visitor;
-
- template <typename Pos, typename Fn>
- static void visit_inner(Pos&& pos, size_t first, Fn&& fn)
- {
- auto f = pos.index(first);
- pos.towards_oh(this_t{}, first, f, fn);
- pos.each_right(for_each_chunk_visitor{}, f + 1, fn);
- }
-
- template <typename Pos, typename Fn>
- static void visit_leaf(Pos&& pos, size_t first, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- auto f = pos.index(first);
- fn(data + f, data + pos.count());
- }
-};
-
-struct for_each_chunk_i_visitor : visitor_base<for_each_chunk_i_visitor>
-{
- using this_t = for_each_chunk_i_visitor;
-
- template <typename Pos, typename Fn>
- static void visit_relaxed(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- // we are going towards *two* indices, so we need to do the
- // relaxed as a special case to correct the second index
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- if (f == l) {
- auto sbh = pos.size_before(f);
- pos.towards_oh_sbh(this_t{}, first, f, sbh, last - sbh, fn);
- } else {
- assert(f < l);
- pos.towards_oh(for_each_chunk_right_visitor{}, first, f, fn);
- pos.each_i(for_each_chunk_visitor{}, f + 1, l, fn);
- pos.towards_oh(for_each_chunk_left_visitor{}, last - 1, l, fn);
- }
- }
- }
-
- template <typename Pos, typename Fn>
- static void visit_regular(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- if (f == l)
- pos.towards_oh(this_t{}, first, f, last, fn);
- else {
- assert(f < l);
- pos.towards_oh(for_each_chunk_right_visitor{}, first, f, fn);
- pos.each_i(for_each_chunk_visitor{}, f + 1, l, fn);
- pos.towards_oh(for_each_chunk_left_visitor{}, last - 1, l, fn);
- }
- }
- }
-
- template <typename Pos, typename Fn>
- static void visit_leaf(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- fn(data + f, data + l + 1);
- }
- }
-};
-
-struct for_each_chunk_p_left_visitor
- : visitor_base<for_each_chunk_p_left_visitor>
-{
- using this_t = for_each_chunk_p_left_visitor;
-
- template <typename Pos, typename Fn>
- static bool visit_inner(Pos&& pos, size_t last, Fn&& fn)
- {
- auto l = pos.index(last);
- return pos.each_pred_left(for_each_chunk_p_visitor{}, l, fn) &&
- pos.towards_oh(this_t{}, last, l, fn);
- }
-
- template <typename Pos, typename Fn>
- static bool visit_leaf(Pos&& pos, size_t last, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- auto l = pos.index(last);
- return fn(data, data + l + 1);
- }
-};
-
-struct for_each_chunk_p_right_visitor
- : visitor_base<for_each_chunk_p_right_visitor>
-{
- using this_t = for_each_chunk_p_right_visitor;
-
- template <typename Pos, typename Fn>
- static bool visit_inner(Pos&& pos, size_t first, Fn&& fn)
- {
- auto f = pos.index(first);
- return pos.towards_oh(this_t{}, first, f, fn) &&
- pos.each_pred_right(for_each_chunk_p_visitor{}, f + 1, fn);
- }
-
- template <typename Pos, typename Fn>
- static bool visit_leaf(Pos&& pos, size_t first, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- auto f = pos.index(first);
- return fn(data + f, data + pos.count());
- }
-};
-
-struct for_each_chunk_p_i_visitor : visitor_base<for_each_chunk_p_i_visitor>
-{
- using this_t = for_each_chunk_p_i_visitor;
-
- template <typename Pos, typename Fn>
- static bool visit_relaxed(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- // we are going towards *two* indices, so we need to do the
- // relaxed as a special case to correct the second index
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- if (f == l) {
- auto sbh = pos.size_before(f);
- return pos.towards_oh_sbh(
- this_t{}, first, f, sbh, last - sbh, fn);
- } else {
- assert(f < l);
- return pos.towards_oh(
- for_each_chunk_p_right_visitor{}, first, f, fn) &&
- pos.each_pred_i(
- for_each_chunk_p_visitor{}, f + 1, l, fn) &&
- pos.towards_oh(
- for_each_chunk_p_left_visitor{}, last - 1, l, fn);
- }
- }
- return true;
- }
-
- template <typename Pos, typename Fn>
- static bool visit_regular(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- if (f == l)
- return pos.towards_oh(this_t{}, first, f, last, fn);
- else {
- assert(f < l);
- return pos.towards_oh(
- for_each_chunk_p_right_visitor{}, first, f, fn) &&
- pos.each_pred_i(
- for_each_chunk_p_visitor{}, f + 1, l, fn) &&
- pos.towards_oh(
- for_each_chunk_p_left_visitor{}, last - 1, l, fn);
- }
- }
- return true;
- }
-
- template <typename Pos, typename Fn>
- static bool visit_leaf(Pos&& pos, size_t first, size_t last, Fn&& fn)
- {
- auto data = pos.node()->leaf();
- if (first < last) {
- auto f = pos.index(first);
- auto l = pos.index(last - 1);
- return fn(data + f, data + l + 1);
- }
- return true;
- }
-};
-
-struct equals_visitor : visitor_base<equals_visitor>
-{
- using this_t = equals_visitor;
-
- struct this_aux_t : visitor_base<this_aux_t>
- {
- template <typename PosR, typename PosL, typename Iter>
- static bool visit_inner(
- PosR&& posr, count_t i, PosL&& posl, Iter&& first, size_t idx)
- {
- return posl.nth_sub(i, this_t{}, posr, first, idx);
- }
-
- template <typename PosR, typename PosL, typename Iter>
- static bool visit_leaf(
- PosR&& posr, count_t i, PosL&& posl, Iter&& first, size_t idx)
- {
- return posl.nth_sub_leaf(i, this_t{}, posr, first, idx);
- }
- };
-
- struct rrb : visitor_base<rrb>
- {
- template <typename PosR, typename Iter, typename Node>
- static bool visit_node(PosR&& posr,
- Iter&& first,
- Node* rootl,
- shift_t shiftl,
- size_t sizel)
- {
- assert(shiftl <= posr.shift());
- return shiftl == posr.shift()
- ? visit_maybe_relaxed_sub(rootl,
- shiftl,
- sizel,
- this_t{},
- posr,
- first,
- size_t{})
- : posr.first_sub_inner(
- rrb{}, first, rootl, shiftl, sizel);
- }
- };
-
- template <typename Iter>
- static auto equal_chunk_p(Iter&& iter)
- {
- return [iter](auto f, auto e) mutable {
- if (f == &*iter) {
- iter += e - f;
- return true;
- }
- for (; f != e; ++f, ++iter)
- if (*f != *iter)
- return false;
- return true;
- };
- }
-
- template <typename PosL, typename PosR, typename Iter>
- static bool
- visit_relaxed(PosL&& posl, PosR&& posr, Iter&& first, size_t idx)
- {
- auto nl = posl.node();
- auto nr = posr.node();
- if (nl == nr)
- return true;
- auto cl = posl.count();
- auto cr = posr.count();
- assert(cr > 0);
- auto sbr = size_t{};
- auto i = count_t{};
- auto j = count_t{};
- for (; i < cl; ++i) {
- auto sbl = posl.size_before(i);
- for (; j + 1 < cr && (sbr = posr.size_before(j)) < sbl; ++j)
- ;
- auto res =
- sbl == sbr
- ? posr.nth_sub(j, this_aux_t{}, i, posl, first, idx + sbl)
- : posl.nth_sub(i,
- for_each_chunk_p_visitor{},
- this_t::equal_chunk_p(first + (idx + sbl)));
- if (!res)
- return false;
- }
- return true;
- }
-
- template <typename PosL, typename PosR, typename Iter>
- static std::enable_if_t<is_relaxed_v<PosR>, bool>
- visit_regular(PosL&& posl, PosR&& posr, Iter&& first, size_t idx)
- {
- return this_t::visit_relaxed(posl, posr, first, idx);
- }
-
- template <typename PosL, typename PosR, typename Iter>
- static std::enable_if_t<!is_relaxed_v<PosR>, bool>
- visit_regular(PosL&& posl, PosR&& posr, Iter&& first, size_t idx)
- {
- return posl.count() >= posr.count()
- ? this_t::visit_regular(posl, posr.node())
- : this_t::visit_regular(posr, posl.node());
- }
-
- template <typename PosL, typename PosR, typename Iter>
- static bool visit_leaf(PosL&& posl, PosR&& posr, Iter&& first, size_t idx)
- {
- if (posl.node() == posr.node())
- return true;
- auto cl = posl.count();
- auto cr = posr.count();
- auto mp = std::min(cl, cr);
- return std::equal(posl.node()->leaf(),
- posl.node()->leaf() + mp,
- posr.node()->leaf()) &&
- std::equal(posl.node()->leaf() + mp,
- posl.node()->leaf() + posl.count(),
- first + (idx + mp));
- }
-
- template <typename Pos, typename NodeT>
- static bool visit_regular(Pos&& pos, NodeT* other)
- {
- auto node = pos.node();
- return node == other || pos.each_pred_zip(this_t{}, other);
- }
-
- template <typename Pos, typename NodeT>
- static bool visit_leaf(Pos&& pos, NodeT* other)
- {
- auto node = pos.node();
- return node == other || std::equal(node->leaf(),
- node->leaf() + pos.count(),
- other->leaf());
- }
-};
-
-template <typename NodeT>
-struct update_visitor : visitor_base<update_visitor<NodeT>>
-{
- using node_t = NodeT;
- using this_t = update_visitor;
-
- template <typename Pos, typename Fn>
- static node_t* visit_relaxed(Pos&& pos, size_t idx, Fn&& fn)
- {
- auto offset = pos.index(idx);
- auto count = pos.count();
- auto node = node_t::make_inner_sr_n(count, pos.relaxed());
- IMMER_TRY {
- auto child = pos.towards_oh(this_t{}, idx, offset, fn);
- node_t::do_copy_inner_replace_sr(
- node, pos.node(), count, offset, child);
- return node;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_r(node, count);
- IMMER_RETHROW;
- }
- }
-
- template <typename Pos, typename Fn>
- static node_t* visit_regular(Pos&& pos, size_t idx, Fn&& fn)
- {
- auto offset = pos.index(idx);
- auto count = pos.count();
- auto node = node_t::make_inner_n(count);
- IMMER_TRY {
- auto child = pos.towards_oh_ch(this_t{}, idx, offset, count, fn);
- node_t::do_copy_inner_replace(
- node, pos.node(), count, offset, child);
- return node;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner(node, count);
- IMMER_RETHROW;
- }
- }
-
- template <typename Pos, typename Fn>
- static node_t* visit_leaf(Pos&& pos, size_t idx, Fn&& fn)
- {
- auto offset = pos.index(idx);
- auto node = node_t::copy_leaf(pos.node(), pos.count());
- IMMER_TRY {
- node->leaf()[offset] =
- std::forward<Fn>(fn)(std::move(node->leaf()[offset]));
- return node;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(node, pos.count());
- IMMER_RETHROW;
- }
- }
-};
-
-struct dec_visitor : visitor_base<dec_visitor>
-{
- using this_t = dec_visitor;
-
- template <typename Pos>
- static void visit_relaxed(Pos&& p)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each(this_t{});
- node_t::delete_inner_r(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_regular(Pos&& p)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each(this_t{});
- node_t::delete_inner(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_leaf(Pos&& p)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- node_t::delete_leaf(node, p.count());
- }
- }
-};
-
-template <typename NodeT>
-void dec_leaf(NodeT* node, count_t n)
-{
- make_leaf_sub_pos(node, n).visit(dec_visitor{});
-}
-
-template <typename NodeT>
-void dec_inner(NodeT* node, shift_t shift, size_t size)
-{
- visit_maybe_relaxed_sub(node, shift, size, dec_visitor());
-}
-
-template <typename NodeT>
-void dec_relaxed(NodeT* node, shift_t shift)
-{
- make_relaxed_pos(node, shift, node->relaxed()).visit(dec_visitor());
-}
-
-template <typename NodeT>
-void dec_regular(NodeT* node, shift_t shift, size_t size)
-{
- make_regular_pos(node, shift, size).visit(dec_visitor());
-}
-
-template <typename NodeT>
-void dec_empty_regular(NodeT* node)
-{
- make_empty_regular_pos(node).visit(dec_visitor());
-}
-
-template <typename NodeT>
-struct get_mut_visitor : visitor_base<get_mut_visitor<NodeT>>
-{
- using node_t = NodeT;
- using this_t = get_mut_visitor;
- using value_t = typename NodeT::value_t;
- using edit_t = typename NodeT::edit_t;
-
- template <typename Pos>
- static value_t&
- visit_relaxed(Pos&& pos, size_t idx, edit_t e, node_t** location)
- {
- auto offset = pos.index(idx);
- auto count = pos.count();
- auto node = pos.node();
- if (node->can_mutate(e)) {
- return pos.towards_oh(
- this_t{}, idx, offset, e, &node->inner()[offset]);
- } else {
- auto new_node = node_t::copy_inner_sr_e(e, node, count);
- IMMER_TRY {
- auto& res = pos.towards_oh(
- this_t{}, idx, offset, e, &new_node->inner()[offset]);
- pos.visit(dec_visitor{});
- *location = new_node;
- return res;
- }
- IMMER_CATCH (...) {
- dec_relaxed(new_node, pos.shift());
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename Pos>
- static value_t&
- visit_regular(Pos&& pos, size_t idx, edit_t e, node_t** location)
- {
- assert(pos.node() == *location);
- auto offset = pos.index(idx);
- auto count = pos.count();
- auto node = pos.node();
- if (node->can_mutate(e)) {
- return pos.towards_oh_ch(
- this_t{}, idx, offset, count, e, &node->inner()[offset]);
- } else {
- auto new_node = node_t::copy_inner_e(e, node, count);
- IMMER_TRY {
- auto& res = pos.towards_oh_ch(this_t{},
- idx,
- offset,
- count,
- e,
- &new_node->inner()[offset]);
- pos.visit(dec_visitor{});
- *location = new_node;
- return res;
- }
- IMMER_CATCH (...) {
- dec_regular(new_node, pos.shift(), pos.size());
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename Pos>
- static value_t&
- visit_leaf(Pos&& pos, size_t idx, edit_t e, node_t** location)
- {
- assert(pos.node() == *location);
- auto node = pos.node();
- if (node->can_mutate(e)) {
- return node->leaf()[pos.index(idx)];
- } else {
- auto new_node = node_t::copy_leaf_e(e, pos.node(), pos.count());
- pos.visit(dec_visitor{});
- *location = new_node;
- return new_node->leaf()[pos.index(idx)];
- }
- }
-};
-
-template <typename NodeT, bool Mutating = true>
-struct push_tail_mut_visitor
- : visitor_base<push_tail_mut_visitor<NodeT, Mutating>>
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using this_t = push_tail_mut_visitor;
- using this_no_mut_t = push_tail_mut_visitor<NodeT, false>;
- using node_t = NodeT;
- using edit_t = typename NodeT::edit_t;
-
- template <typename Pos>
- static node_t* visit_relaxed(Pos&& pos, edit_t e, node_t* tail, count_t ts)
- {
- auto node = pos.node();
- auto level = pos.shift();
- auto idx = pos.count() - 1;
- auto children = pos.size(idx);
- auto new_idx =
- children == size_t{1} << level || level == BL ? idx + 1 : idx;
- auto new_child = static_cast<node_t*>(nullptr);
- auto mutate = Mutating && node->can_mutate(e);
-
- if (new_idx >= branches<B>)
- return nullptr;
- else if (idx == new_idx) {
- new_child =
- mutate ? pos.last_oh_csh(this_t{}, idx, children, e, tail, ts)
- : pos.last_oh_csh(
- this_no_mut_t{}, idx, children, e, tail, ts);
- if (!new_child) {
- if (++new_idx < branches<B>)
- new_child = node_t::make_path_e(e, level - B, tail);
- else
- return nullptr;
- }
- } else
- new_child = node_t::make_path_e(e, level - B, tail);
-
- if (mutate) {
- auto count = new_idx + 1;
- auto relaxed = node->ensure_mutable_relaxed_n(e, new_idx);
- node->inner()[new_idx] = new_child;
- relaxed->d.sizes[new_idx] = pos.size() + ts;
- relaxed->d.count = count;
- assert(relaxed->d.sizes[new_idx]);
- return node;
- } else {
- IMMER_TRY {
- auto count = new_idx + 1;
- auto new_node = node_t::copy_inner_r_e(e, pos.node(), new_idx);
- auto relaxed = new_node->relaxed();
- new_node->inner()[new_idx] = new_child;
- relaxed->d.sizes[new_idx] = pos.size() + ts;
- relaxed->d.count = count;
- assert(relaxed->d.sizes[new_idx]);
- if (Mutating)
- pos.visit(dec_visitor{});
- return new_node;
- }
- IMMER_CATCH (...) {
- auto shift = pos.shift();
- auto size = new_idx == idx ? children + ts : ts;
- if (shift > BL) {
- tail->inc();
- dec_inner(new_child, shift - B, size);
- }
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename Pos, typename... Args>
- static node_t* visit_regular(Pos&& pos, edit_t e, node_t* tail, Args&&...)
- {
- assert((pos.size() & mask<BL>) == 0);
- auto node = pos.node();
- auto idx = pos.index(pos.size() - 1);
- auto new_idx = pos.index(pos.size() + branches<BL> - 1);
- auto mutate = Mutating && node->can_mutate(e);
- if (mutate) {
- node->inner()[new_idx] =
- idx == new_idx ? pos.last_oh(this_t{}, idx, e, tail)
- /* otherwise */
- : node_t::make_path_e(e, pos.shift() - B, tail);
- return node;
- } else {
- auto new_parent = node_t::make_inner_e(e);
- IMMER_TRY {
- new_parent->inner()[new_idx] =
- idx == new_idx
- ? pos.last_oh(this_no_mut_t{}, idx, e, tail)
- /* otherwise */
- : node_t::make_path_e(e, pos.shift() - B, tail);
- node_t::do_copy_inner(new_parent, node, new_idx);
- if (Mutating)
- pos.visit(dec_visitor{});
- return new_parent;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_e(new_parent);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename Pos, typename... Args>
- static node_t* visit_leaf(Pos&& pos, edit_t e, node_t* tail, Args&&...)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-template <typename NodeT>
-struct push_tail_visitor : visitor_base<push_tail_visitor<NodeT>>
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using this_t = push_tail_visitor;
- using node_t = NodeT;
-
- template <typename Pos>
- static node_t* visit_relaxed(Pos&& pos, node_t* tail, count_t ts)
- {
- auto level = pos.shift();
- auto idx = pos.count() - 1;
- auto children = pos.size(idx);
- auto new_idx =
- children == size_t{1} << level || level == BL ? idx + 1 : idx;
- auto new_child = static_cast<node_t*>(nullptr);
- if (new_idx >= branches<B>)
- return nullptr;
- else if (idx == new_idx) {
- new_child = pos.last_oh_csh(this_t{}, idx, children, tail, ts);
- if (!new_child) {
- if (++new_idx < branches<B>)
- new_child = node_t::make_path(level - B, tail);
- else
- return nullptr;
- }
- } else
- new_child = node_t::make_path(level - B, tail);
- IMMER_TRY {
- auto count = new_idx + 1;
- auto new_parent =
- node_t::copy_inner_r_n(count, pos.node(), new_idx);
- auto new_relaxed = new_parent->relaxed();
- new_parent->inner()[new_idx] = new_child;
- new_relaxed->d.sizes[new_idx] = pos.size() + ts;
- new_relaxed->d.count = count;
- assert(new_relaxed->d.sizes[new_idx]);
- return new_parent;
- }
- IMMER_CATCH (...) {
- auto shift = pos.shift();
- auto size = new_idx == idx ? children + ts : ts;
- if (shift > BL) {
- tail->inc();
- dec_inner(new_child, shift - B, size);
- }
- IMMER_RETHROW;
- }
- }
-
- template <typename Pos, typename... Args>
- static node_t* visit_regular(Pos&& pos, node_t* tail, Args&&...)
- {
- assert((pos.size() & mask<BL>) == 0);
- auto idx = pos.index(pos.size() - 1);
- auto new_idx = pos.index(pos.size() + branches<BL> - 1);
- auto count = new_idx + 1;
- auto new_parent = node_t::make_inner_n(count);
- IMMER_TRY {
- new_parent->inner()[new_idx] =
- idx == new_idx ? pos.last_oh(this_t{}, idx, tail)
- /* otherwise */
- : node_t::make_path(pos.shift() - B, tail);
- }
- IMMER_CATCH (...) {
- node_t::delete_inner(new_parent, count);
- IMMER_RETHROW;
- }
- return node_t::do_copy_inner(new_parent, pos.node(), new_idx);
- }
-
- template <typename Pos, typename... Args>
- static node_t* visit_leaf(Pos&& pos, node_t* tail, Args&&...)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-struct dec_right_visitor : visitor_base<dec_right_visitor>
-{
- using this_t = dec_right_visitor;
- using dec_t = dec_visitor;
-
- template <typename Pos>
- static void visit_relaxed(Pos&& p, count_t idx)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each_right(dec_t{}, idx);
- node_t::delete_inner_r(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_regular(Pos&& p, count_t idx)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each_right(dec_t{}, idx);
- node_t::delete_inner(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_leaf(Pos&& p, count_t idx)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-template <typename NodeT, bool Collapse = true, bool Mutating = true>
-struct slice_right_mut_visitor
- : visitor_base<slice_right_mut_visitor<NodeT, Collapse, Mutating>>
-{
- using node_t = NodeT;
- using this_t = slice_right_mut_visitor;
- using edit_t = typename NodeT::edit_t;
-
- // returns a new shift, new root, the new tail size and the new tail
- using result_t = std::tuple<shift_t, NodeT*, count_t, NodeT*>;
- using no_collapse_t = slice_right_mut_visitor<NodeT, false, true>;
- using no_collapse_no_mut_t = slice_right_mut_visitor<NodeT, false, false>;
- using no_mut_t = slice_right_mut_visitor<NodeT, Collapse, false>;
-
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- template <typename PosT>
- static result_t visit_relaxed(PosT&& pos, size_t last, edit_t e)
- {
- auto idx = pos.index(last);
- auto node = pos.node();
- auto mutate = Mutating && node->can_mutate(e);
- if (Collapse && idx == 0) {
- auto res = mutate ? pos.towards_oh(this_t{}, last, idx, e)
- : pos.towards_oh(no_mut_t{}, last, idx, e);
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{1});
- return res;
- } else {
- using std::get;
- auto subs =
- mutate ? pos.towards_oh(no_collapse_t{}, last, idx, e)
- : pos.towards_oh(no_collapse_no_mut_t{}, last, idx, e);
- auto next = get<1>(subs);
- auto ts = get<2>(subs);
- auto tail = get<3>(subs);
- IMMER_TRY {
- if (next) {
- if (mutate) {
- auto nodr = node->ensure_mutable_relaxed_n(e, idx);
- pos.each_right(dec_visitor{}, idx + 1);
- node->inner()[idx] = next;
- nodr->d.sizes[idx] = last + 1 - ts;
- nodr->d.count = idx + 1;
- assert(nodr->d.sizes[idx]);
- return std::make_tuple(pos.shift(), node, ts, tail);
- } else {
- auto newn = node_t::copy_inner_r_e(e, node, idx);
- auto newr = newn->relaxed();
- newn->inner()[idx] = next;
- newr->d.sizes[idx] = last + 1 - ts;
- newr->d.count = idx + 1;
- assert(newr->d.sizes[idx]);
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- } else if (idx == 0) {
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{1});
- return std::make_tuple(pos.shift(), nullptr, ts, tail);
- } else if (Collapse && idx == 1 && pos.shift() > BL) {
- auto newn = pos.node()->inner()[0];
- if (!mutate)
- newn->inc();
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{2});
- return std::make_tuple(pos.shift() - B, newn, ts, tail);
- } else {
- if (mutate) {
- pos.each_right(dec_visitor{}, idx + 1);
- node->ensure_mutable_relaxed_n(e, idx)->d.count = idx;
- return std::make_tuple(pos.shift(), node, ts, tail);
- } else {
- auto newn = node_t::copy_inner_r_e(e, node, idx);
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- }
- }
- IMMER_CATCH (...) {
- assert(!mutate);
- assert(!next || pos.shift() > BL);
- if (next)
- dec_inner(next,
- pos.shift() - B,
- last + 1 - ts - pos.size_before(idx));
- dec_leaf(tail, ts);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_regular(PosT&& pos, size_t last, edit_t e)
- {
- auto idx = pos.index(last);
- auto node = pos.node();
- auto mutate = Mutating && node->can_mutate(e);
- if (Collapse && idx == 0) {
- auto res = mutate ? pos.towards_oh(this_t{}, last, idx, e)
- : pos.towards_oh(no_mut_t{}, last, idx, e);
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{1});
- return res;
- } else {
- using std::get;
- auto subs =
- mutate ? pos.towards_oh(no_collapse_t{}, last, idx, e)
- : pos.towards_oh(no_collapse_no_mut_t{}, last, idx, e);
- auto next = get<1>(subs);
- auto ts = get<2>(subs);
- auto tail = get<3>(subs);
- IMMER_TRY {
- if (next) {
- if (mutate) {
- node->inner()[idx] = next;
- pos.each_right(dec_visitor{}, idx + 1);
- return std::make_tuple(pos.shift(), node, ts, tail);
- } else {
- auto newn = node_t::copy_inner_e(e, node, idx);
- newn->inner()[idx] = next;
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- } else if (idx == 0) {
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{1});
- return std::make_tuple(pos.shift(), nullptr, ts, tail);
- } else if (Collapse && idx == 1 && pos.shift() > BL) {
- auto newn = pos.node()->inner()[0];
- if (!mutate)
- newn->inc();
- if (Mutating)
- pos.visit(dec_right_visitor{}, count_t{2});
- return std::make_tuple(pos.shift() - B, newn, ts, tail);
- } else {
- if (mutate) {
- pos.each_right(dec_visitor{}, idx + 1);
- return std::make_tuple(pos.shift(), node, ts, tail);
- } else {
- auto newn = node_t::copy_inner_e(e, node, idx);
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- }
- }
- IMMER_CATCH (...) {
- assert(!mutate);
- assert(!next || pos.shift() > BL);
- assert(tail);
- if (next)
- dec_regular(next, pos.shift() - B, last + 1 - ts);
- dec_leaf(tail, ts);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_leaf(PosT&& pos, size_t last, edit_t e)
- {
- auto old_tail_size = pos.count();
- auto new_tail_size = pos.index(last) + 1;
- auto node = pos.node();
- auto mutate = Mutating && node->can_mutate(e);
- if (new_tail_size == old_tail_size) {
- if (!Mutating)
- node->inc();
- return std::make_tuple(0, nullptr, new_tail_size, node);
- } else if (mutate) {
- detail::destroy_n(node->leaf() + new_tail_size,
- old_tail_size - new_tail_size);
- return std::make_tuple(0, nullptr, new_tail_size, node);
- } else {
- auto new_tail = node_t::copy_leaf_e(e, node, new_tail_size);
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(0, nullptr, new_tail_size, new_tail);
- }
- }
-};
-
-template <typename NodeT, bool Collapse = true>
-struct slice_right_visitor : visitor_base<slice_right_visitor<NodeT, Collapse>>
-{
- using node_t = NodeT;
- using this_t = slice_right_visitor;
-
- // returns a new shift, new root, the new tail size and the new tail
- using result_t = std::tuple<shift_t, NodeT*, count_t, NodeT*>;
- using no_collapse_t = slice_right_visitor<NodeT, false>;
-
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- template <typename PosT>
- static result_t visit_relaxed(PosT&& pos, size_t last)
- {
- auto idx = pos.index(last);
- if (Collapse && idx == 0) {
- return pos.towards_oh(this_t{}, last, idx);
- } else {
- using std::get;
- auto subs = pos.towards_oh(no_collapse_t{}, last, idx);
- auto next = get<1>(subs);
- auto ts = get<2>(subs);
- auto tail = get<3>(subs);
- IMMER_TRY {
- if (next) {
- auto count = idx + 1;
- auto newn = node_t::copy_inner_r_n(count, pos.node(), idx);
- auto newr = newn->relaxed();
- newn->inner()[idx] = next;
- newr->d.sizes[idx] = last + 1 - ts;
- newr->d.count = count;
- assert(newr->d.sizes[idx]);
- return std::make_tuple(pos.shift(), newn, ts, tail);
- } else if (idx == 0) {
- return std::make_tuple(pos.shift(), nullptr, ts, tail);
- } else if (Collapse && idx == 1 && pos.shift() > BL) {
- auto newn = pos.node()->inner()[0];
- return std::make_tuple(
- pos.shift() - B, newn->inc(), ts, tail);
- } else {
- auto newn = node_t::copy_inner_r(pos.node(), idx);
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- }
- IMMER_CATCH (...) {
- assert(!next || pos.shift() > BL);
- if (next)
- dec_inner(next,
- pos.shift() - B,
- last + 1 - ts - pos.size_before(idx));
- if (tail)
- dec_leaf(tail, ts);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_regular(PosT&& pos, size_t last)
- {
- auto idx = pos.index(last);
- if (Collapse && idx == 0) {
- return pos.towards_oh(this_t{}, last, idx);
- } else {
- using std::get;
- auto subs = pos.towards_oh(no_collapse_t{}, last, idx);
- auto next = get<1>(subs);
- auto ts = get<2>(subs);
- auto tail = get<3>(subs);
- IMMER_TRY {
- if (next) {
- auto newn = node_t::copy_inner_n(idx + 1, pos.node(), idx);
- newn->inner()[idx] = next;
- return std::make_tuple(pos.shift(), newn, ts, tail);
- } else if (idx == 0) {
- return std::make_tuple(pos.shift(), nullptr, ts, tail);
- } else if (Collapse && idx == 1 && pos.shift() > BL) {
- auto newn = pos.node()->inner()[0];
- return std::make_tuple(
- pos.shift() - B, newn->inc(), ts, tail);
- } else {
- auto newn = node_t::copy_inner_n(idx, pos.node(), idx);
- return std::make_tuple(pos.shift(), newn, ts, tail);
- }
- }
- IMMER_CATCH (...) {
- assert(!next || pos.shift() > BL);
- assert(tail);
- if (next)
- dec_regular(next, pos.shift() - B, last + 1 - ts);
- dec_leaf(tail, ts);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_leaf(PosT&& pos, size_t last)
- {
- auto old_tail_size = pos.count();
- auto new_tail_size = pos.index(last) + 1;
- auto new_tail = new_tail_size == old_tail_size
- ? pos.node()->inc()
- : node_t::copy_leaf(pos.node(), new_tail_size);
- return std::make_tuple(0, nullptr, new_tail_size, new_tail);
- }
-};
-
-struct dec_left_visitor : visitor_base<dec_left_visitor>
-{
- using this_t = dec_left_visitor;
- using dec_t = dec_visitor;
-
- template <typename Pos>
- static void visit_relaxed(Pos&& p, count_t idx)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each_left(dec_t{}, idx);
- node_t::delete_inner_r(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_regular(Pos&& p, count_t idx)
- {
- using node_t = node_type<Pos>;
- auto node = p.node();
- if (node->dec()) {
- p.each_left(dec_t{}, idx);
- node_t::delete_inner(node, p.count());
- }
- }
-
- template <typename Pos>
- static void visit_leaf(Pos&& p, count_t idx)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-template <typename NodeT, bool Collapse = true, bool Mutating = true>
-struct slice_left_mut_visitor
- : visitor_base<slice_left_mut_visitor<NodeT, Collapse, Mutating>>
-{
- using node_t = NodeT;
- using this_t = slice_left_mut_visitor;
- using edit_t = typename NodeT::edit_t;
- using value_t = typename NodeT::value_t;
- using relaxed_t = typename NodeT::relaxed_t;
- // returns a new shift and new root
- using result_t = std::tuple<shift_t, NodeT*>;
-
- using no_collapse_t = slice_left_mut_visitor<NodeT, false, true>;
- using no_collapse_no_mut_t = slice_left_mut_visitor<NodeT, false, false>;
- using no_mut_t = slice_left_mut_visitor<NodeT, Collapse, false>;
-
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- template <typename PosT>
- static result_t visit_relaxed(PosT&& pos, size_t first, edit_t e)
- {
- auto idx = pos.subindex(first);
- auto count = pos.count();
- auto node = pos.node();
- auto mutate = Mutating && node->can_mutate(e);
- auto left_size = pos.size_before(idx);
- auto child_size = pos.size_sbh(idx, left_size);
- auto dropped_size = first;
- auto child_dropped_size = dropped_size - left_size;
- if (Collapse && pos.shift() > BL && idx == pos.count() - 1) {
- auto r = mutate ? pos.towards_sub_oh(this_t{}, first, idx, e)
- : pos.towards_sub_oh(no_mut_t{}, first, idx, e);
- if (mutate)
- pos.visit(dec_left_visitor{}, idx);
- else if (Mutating)
- pos.visit(dec_visitor{});
- return r;
- } else {
- using std::get;
- auto newn = mutate ? (node->ensure_mutable_relaxed(e), node)
- : node_t::make_inner_r_e(e);
- auto newr = newn->relaxed();
- auto newcount = count - idx;
- auto new_child_size = child_size - child_dropped_size;
- IMMER_TRY {
- auto subs =
- mutate ? pos.towards_sub_oh(no_collapse_t{}, first, idx, e)
- : pos.towards_sub_oh(
- no_collapse_no_mut_t{}, first, idx, e);
- if (mutate)
- pos.each_left(dec_visitor{}, idx);
- pos.copy_sizes(
- idx + 1, newcount - 1, new_child_size, newr->d.sizes + 1);
- std::copy(node->inner() + idx + 1,
- node->inner() + count,
- newn->inner() + 1);
- newn->inner()[0] = get<1>(subs);
- newr->d.sizes[0] = new_child_size;
- newr->d.count = newcount;
- assert(new_child_size);
- if (!mutate) {
- node_t::inc_nodes(newn->inner() + 1, newcount - 1);
- if (Mutating)
- pos.visit(dec_visitor{});
- }
- return std::make_tuple(pos.shift(), newn);
- }
- IMMER_CATCH (...) {
- if (!mutate)
- node_t::delete_inner_r_e(newn);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_regular(PosT&& pos, size_t first, edit_t e)
- {
- auto idx = pos.subindex(first);
- auto count = pos.count();
- auto node = pos.node();
- auto mutate = Mutating
- // this is more restrictive than actually needed because
- // it causes the algorithm to also avoid mutating the leaf
- // in place
- && !node_t::embed_relaxed && node->can_mutate(e);
- auto left_size = pos.size_before(idx);
- auto child_size = pos.size_sbh(idx, left_size);
- auto dropped_size = first;
- auto child_dropped_size = dropped_size - left_size;
- if (Collapse && pos.shift() > BL && idx == pos.count() - 1) {
- auto r = mutate ? pos.towards_sub_oh(this_t{}, first, idx, e)
- : pos.towards_sub_oh(no_mut_t{}, first, idx, e);
- if (mutate)
- pos.visit(dec_left_visitor{}, idx);
- else if (Mutating)
- pos.visit(dec_visitor{});
- return r;
- } else {
- using std::get;
- // if possible, we convert the node to a relaxed one simply by
- // allocating a `relaxed_t` size table for it... maybe some of this
- // magic should be moved as a `node<...>` static method...
- auto newcount = count - idx;
- auto newn =
- mutate ? (node->impl.d.data.inner.relaxed = new (
- node_t::heap::allocate(node_t::max_sizeof_relaxed,
- norefs_tag{})) relaxed_t,
- node)
- : node_t::make_inner_r_e(e);
- auto newr = newn->relaxed();
- IMMER_TRY {
- auto subs =
- mutate ? pos.towards_sub_oh(no_collapse_t{}, first, idx, e)
- : pos.towards_sub_oh(
- no_collapse_no_mut_t{}, first, idx, e);
- if (mutate)
- pos.each_left(dec_visitor{}, idx);
- newr->d.sizes[0] = child_size - child_dropped_size;
- assert(newr->d.sizes[0]);
- pos.copy_sizes(
- idx + 1, newcount - 1, newr->d.sizes[0], newr->d.sizes + 1);
- newr->d.count = newcount;
- newn->inner()[0] = get<1>(subs);
- std::copy(node->inner() + idx + 1,
- node->inner() + count,
- newn->inner() + 1);
- if (!mutate) {
- node_t::inc_nodes(newn->inner() + 1, newcount - 1);
- if (Mutating)
- pos.visit(dec_visitor{});
- }
- return std::make_tuple(pos.shift(), newn);
- }
- IMMER_CATCH (...) {
- if (!mutate)
- node_t::delete_inner_r_e(newn);
- else {
- // restore the regular node that we were
- // attempting to relax...
- node_t::heap::deallocate(node_t::max_sizeof_relaxed,
- node->impl.d.data.inner.relaxed);
- node->impl.d.data.inner.relaxed = nullptr;
- }
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_leaf(PosT&& pos, size_t first, edit_t e)
- {
- auto node = pos.node();
- auto idx = pos.index(first);
- auto count = pos.count();
- auto mutate = Mutating &&
- std::is_nothrow_move_constructible<value_t>::value &&
- node->can_mutate(e);
- if (mutate) {
- auto data = node->leaf();
- auto newcount = count - idx;
- std::move(data + idx, data + count, data);
- detail::destroy_n(data + newcount, idx);
- return std::make_tuple(0, node);
- } else {
- auto newn = node_t::copy_leaf_e(e, node, idx, count);
- if (Mutating)
- pos.visit(dec_visitor{});
- return std::make_tuple(0, newn);
- }
- }
-};
-
-template <typename NodeT, bool Collapse = true>
-struct slice_left_visitor : visitor_base<slice_left_visitor<NodeT, Collapse>>
-{
- using node_t = NodeT;
- using this_t = slice_left_visitor;
-
- // returns a new shift and new root
- using result_t = std::tuple<shift_t, NodeT*>;
- using no_collapse_t = slice_left_visitor<NodeT, false>;
-
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- template <typename PosT>
- static result_t visit_inner(PosT&& pos, size_t first)
- {
- auto idx = pos.subindex(first);
- auto count = pos.count();
- auto left_size = pos.size_before(idx);
- auto child_size = pos.size_sbh(idx, left_size);
- auto dropped_size = first;
- auto child_dropped_size = dropped_size - left_size;
- if (Collapse && pos.shift() > BL && idx == pos.count() - 1) {
- return pos.towards_sub_oh(this_t{}, first, idx);
- } else {
- using std::get;
- auto n = pos.node();
- auto newc = count - idx;
- auto newn = node_t::make_inner_r_n(newc);
- IMMER_TRY {
- auto subs = pos.towards_sub_oh(no_collapse_t{}, first, idx);
- auto newr = newn->relaxed();
- newr->d.count = count - idx;
- newr->d.sizes[0] = child_size - child_dropped_size;
- assert(newr->d.sizes[0]);
- pos.copy_sizes(idx + 1,
- newr->d.count - 1,
- newr->d.sizes[0],
- newr->d.sizes + 1);
- assert(newr->d.sizes[newr->d.count - 1] ==
- pos.size() - dropped_size);
- newn->inner()[0] = get<1>(subs);
- std::copy(n->inner() + idx + 1,
- n->inner() + count,
- newn->inner() + 1);
- node_t::inc_nodes(newn->inner() + 1, newr->d.count - 1);
- return std::make_tuple(pos.shift(), newn);
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_r(newn, newc);
- IMMER_RETHROW;
- }
- }
- }
-
- template <typename PosT>
- static result_t visit_leaf(PosT&& pos, size_t first)
- {
- auto n = node_t::copy_leaf(pos.node(), pos.index(first), pos.count());
- return std::make_tuple(0, n);
- }
-};
-
-template <typename Node>
-struct concat_center_pos
-{
- static constexpr auto B = Node::bits;
- static constexpr auto BL = Node::bits_leaf;
-
- static constexpr count_t max_children = 3;
-
- using node_t = Node;
- using edit_t = typename Node::edit_t;
-
- shift_t shift_ = 0u;
- count_t count_ = 0u;
- node_t* nodes_[max_children];
- size_t sizes_[max_children];
-
- auto shift() const { return shift_; }
-
- concat_center_pos(shift_t s, Node* n0, size_t s0)
- : shift_{s}
- , count_{1}
- , nodes_{n0}
- , sizes_{s0}
- {}
-
- concat_center_pos(shift_t s, Node* n0, size_t s0, Node* n1, size_t s1)
- : shift_{s}
- , count_{2}
- , nodes_{n0, n1}
- , sizes_{s0, s0 + s1}
- {}
-
- concat_center_pos(shift_t s,
- Node* n0,
- size_t s0,
- Node* n1,
- size_t s1,
- Node* n2,
- size_t s2)
- : shift_{s}
- , count_{3}
- , nodes_{n0, n1, n2}
- , sizes_{s0, s0 + s1, s0 + s1 + s2}
- {}
-
- template <typename Visitor, typename... Args>
- void each_sub(Visitor v, Args&&... args)
- {
- if (shift_ == BL) {
- auto s = size_t{};
- for (auto i = count_t{0}; i < count_; ++i) {
- make_leaf_sub_pos(nodes_[i], sizes_[i] - s).visit(v, args...);
- s = sizes_[i];
- }
- } else {
- for (auto i = count_t{0}; i < count_; ++i)
- make_relaxed_pos(nodes_[i], shift_ - B, nodes_[i]->relaxed())
- .visit(v, args...);
- }
- }
-
- relaxed_pos<Node> realize() &&
- {
- if (count_ > 1) {
- IMMER_TRY {
- auto result = node_t::make_inner_r_n(count_);
- auto r = result->relaxed();
- r->d.count = count_;
- std::copy(nodes_, nodes_ + count_, result->inner());
- std::copy(sizes_, sizes_ + count_, r->d.sizes);
- return {result, shift_, r};
- }
- IMMER_CATCH (...) {
- each_sub(dec_visitor{});
- IMMER_RETHROW;
- }
- } else {
- assert(shift_ >= B + BL);
- return {nodes_[0], shift_ - B, nodes_[0]->relaxed()};
- }
- }
-
- relaxed_pos<Node> realize_e(edit_t e)
- {
- if (count_ > 1) {
- auto result = node_t::make_inner_r_e(e);
- auto r = result->relaxed();
- r->d.count = count_;
- std::copy(nodes_, nodes_ + count_, result->inner());
- std::copy(sizes_, sizes_ + count_, r->d.sizes);
- return {result, shift_, r};
- } else {
- assert(shift_ >= B + BL);
- return {nodes_[0], shift_ - B, nodes_[0]->relaxed()};
- }
- }
-};
-
-template <typename Node>
-struct concat_merger
-{
- using node_t = Node;
- static constexpr auto B = Node::bits;
- static constexpr auto BL = Node::bits_leaf;
-
- using result_t = concat_center_pos<Node>;
-
- count_t* curr_;
- count_t n_;
- result_t result_;
-
- concat_merger(shift_t shift, count_t* counts, count_t n)
- : curr_{counts}
- , n_{n}
- , result_{
- shift + B, node_t::make_inner_r_n(std::min(n_, branches<B>)), 0}
- {}
-
- node_t* to_ = {};
- count_t to_offset_ = {};
- size_t to_size_ = {};
-
- void add_child(node_t* p, size_t size)
- {
- assert(size);
- ++curr_;
- auto parent = result_.nodes_[result_.count_ - 1];
- auto relaxed = parent->relaxed();
- if (relaxed->d.count == branches<B>) {
- assert(result_.count_ < result_t::max_children);
- n_ -= branches<B>;
- parent = node_t::make_inner_r_n(std::min(n_, branches<B>));
- relaxed = parent->relaxed();
- result_.nodes_[result_.count_] = parent;
- result_.sizes_[result_.count_] = result_.sizes_[result_.count_ - 1];
- assert(result_.sizes_[result_.count_]);
- ++result_.count_;
- }
- auto idx = relaxed->d.count++;
- result_.sizes_[result_.count_ - 1] += size;
- assert(result_.sizes_[result_.count_ - 1]);
- relaxed->d.sizes[idx] = size + (idx ? relaxed->d.sizes[idx - 1] : 0);
- assert(relaxed->d.sizes[idx]);
- parent->inner()[idx] = p;
- };
-
- template <typename Pos>
- void merge_leaf(Pos&& p)
- {
- auto from = p.node();
- auto from_size = p.size();
- auto from_count = p.count();
- assert(from_size);
- if (!to_ && *curr_ == from_count) {
- add_child(from, from_size);
- from->inc();
- } else {
- auto from_offset = count_t{};
- auto from_data = from->leaf();
- do {
- if (!to_) {
- to_ = node_t::make_leaf_n(*curr_);
- to_offset_ = 0;
- }
- auto data = to_->leaf();
- auto to_copy =
- std::min(from_count - from_offset, *curr_ - to_offset_);
- detail::uninitialized_copy(from_data + from_offset,
- from_data + from_offset + to_copy,
- data + to_offset_);
- to_offset_ += to_copy;
- from_offset += to_copy;
- if (*curr_ == to_offset_) {
- add_child(to_, to_offset_);
- to_ = nullptr;
- }
- } while (from_offset != from_count);
- }
- }
-
- template <typename Pos>
- void merge_inner(Pos&& p)
- {
- auto from = p.node();
- auto from_size = p.size();
- auto from_count = p.count();
- assert(from_size);
- if (!to_ && *curr_ == from_count) {
- add_child(from, from_size);
- from->inc();
- } else {
- auto from_offset = count_t{};
- auto from_data = from->inner();
- do {
- if (!to_) {
- to_ = node_t::make_inner_r_n(*curr_);
- to_offset_ = 0;
- to_size_ = 0;
- }
- auto data = to_->inner();
- auto to_copy =
- std::min(from_count - from_offset, *curr_ - to_offset_);
- std::copy(from_data + from_offset,
- from_data + from_offset + to_copy,
- data + to_offset_);
- node_t::inc_nodes(from_data + from_offset, to_copy);
- auto sizes = to_->relaxed()->d.sizes;
- p.copy_sizes(
- from_offset, to_copy, to_size_, sizes + to_offset_);
- to_offset_ += to_copy;
- from_offset += to_copy;
- to_size_ = sizes[to_offset_ - 1];
- assert(to_size_);
- if (*curr_ == to_offset_) {
- to_->relaxed()->d.count = to_offset_;
- add_child(to_, to_size_);
- to_ = nullptr;
- }
- } while (from_offset != from_count);
- }
- }
-
- concat_center_pos<Node> finish() const
- {
- assert(!to_);
- return result_;
- }
-
- void abort()
- {
- auto shift = result_.shift_ - B;
- if (to_) {
- if (shift == BL)
- node_t::delete_leaf(to_, to_offset_);
- else {
- to_->relaxed()->d.count = to_offset_;
- dec_relaxed(to_, shift - B);
- }
- }
- result_.each_sub(dec_visitor());
- }
-};
-
-struct concat_merger_visitor : visitor_base<concat_merger_visitor>
-{
- using this_t = concat_merger_visitor;
-
- template <typename Pos, typename Merger>
- static void visit_inner(Pos&& p, Merger& merger)
- {
- merger.merge_inner(p);
- }
-
- template <typename Pos, typename Merger>
- static void visit_leaf(Pos&& p, Merger& merger)
- {
- merger.merge_leaf(p);
- }
-};
-
-struct concat_rebalance_plan_fill_visitor
- : visitor_base<concat_rebalance_plan_fill_visitor>
-{
- using this_t = concat_rebalance_plan_fill_visitor;
-
- template <typename Pos, typename Plan>
- static void visit_node(Pos&& p, Plan& plan)
- {
- auto count = p.count();
- assert(plan.n < Plan::max_children);
- plan.counts[plan.n++] = count;
- plan.total += count;
- }
-};
-
-template <bits_t B, bits_t BL>
-struct concat_rebalance_plan
-{
- static constexpr auto max_children = 2 * branches<B> + 1;
-
- count_t counts[max_children];
- count_t n = 0u;
- count_t total = 0u;
-
- template <typename LPos, typename CPos, typename RPos>
- void fill(LPos&& lpos, CPos&& cpos, RPos&& rpos)
- {
- assert(n == 0u);
- assert(total == 0u);
- using visitor_t = concat_rebalance_plan_fill_visitor;
- lpos.each_left_sub(visitor_t{}, *this);
- cpos.each_sub(visitor_t{}, *this);
- rpos.each_right_sub(visitor_t{}, *this);
- }
-
- void shuffle(shift_t shift)
- {
- // gcc seems to not really understand this code... :(
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
- constexpr count_t rrb_extras = 2;
- constexpr count_t rrb_invariant = 1;
- const auto bits = shift == BL ? BL : B;
- const auto branches = count_t{1} << bits;
- const auto optimal = ((total - 1) >> bits) + 1;
- count_t i = 0;
- while (n >= optimal + rrb_extras) {
- // skip ok nodes
- while (counts[i] > branches - rrb_invariant)
- i++;
- assert(i < n);
- // short node, redistribute
- auto remaining = counts[i];
- do {
- auto next = counts[i + 1];
- auto count = std::min(remaining + next, branches);
- counts[i] = count;
- assert(counts[i]);
- remaining += next - count;
- ++i;
- } while (remaining > 0);
- // remove node
- std::move(counts + i + 1, counts + n, counts + i);
- --n;
- --i;
- }
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic pop
-#endif
- }
-
- template <typename LPos, typename CPos, typename RPos>
- concat_center_pos<node_type<CPos>>
- merge(LPos&& lpos, CPos&& cpos, RPos&& rpos)
- {
- using node_t = node_type<CPos>;
- using merger_t = concat_merger<node_t>;
- using visitor_t = concat_merger_visitor;
- auto merger = merger_t{cpos.shift(), counts, n};
- IMMER_TRY {
- lpos.each_left_sub(visitor_t{}, merger);
- cpos.each_sub(visitor_t{}, merger);
- rpos.each_right_sub(visitor_t{}, merger);
- cpos.each_sub(dec_visitor{});
- return merger.finish();
- }
- IMMER_CATCH (...) {
- merger.abort();
- IMMER_RETHROW;
- }
- }
-};
-
-template <typename Node, typename LPos, typename CPos, typename RPos>
-concat_center_pos<Node> concat_rebalance(LPos&& lpos, CPos&& cpos, RPos&& rpos)
-{
- auto plan = concat_rebalance_plan<Node::bits, Node::bits_leaf>{};
- plan.fill(lpos, cpos, rpos);
- plan.shuffle(cpos.shift());
- IMMER_TRY {
- return plan.merge(lpos, cpos, rpos);
- }
- IMMER_CATCH (...) {
- cpos.each_sub(dec_visitor{});
- IMMER_RETHROW;
- }
-}
-
-template <typename Node, typename LPos, typename TPos, typename RPos>
-concat_center_pos<Node> concat_leafs(LPos&& lpos, TPos&& tpos, RPos&& rpos)
-{
- static_assert(Node::bits >= 2, "");
- assert(lpos.shift() == tpos.shift());
- assert(lpos.shift() == rpos.shift());
- assert(lpos.shift() == 0);
- if (tpos.count() > 0)
- return {
- Node::bits_leaf,
- lpos.node()->inc(),
- lpos.count(),
- tpos.node()->inc(),
- tpos.count(),
- rpos.node()->inc(),
- rpos.count(),
- };
- else
- return {
- Node::bits_leaf,
- lpos.node()->inc(),
- lpos.count(),
- rpos.node()->inc(),
- rpos.count(),
- };
-}
-
-template <typename Node>
-struct concat_left_visitor;
-template <typename Node>
-struct concat_right_visitor;
-template <typename Node>
-struct concat_both_visitor;
-
-template <typename Node, typename LPos, typename TPos, typename RPos>
-concat_center_pos<Node> concat_inners(LPos&& lpos, TPos&& tpos, RPos&& rpos)
-{
- auto lshift = lpos.shift();
- auto rshift = rpos.shift();
- if (lshift > rshift) {
- auto cpos = lpos.last_sub(concat_left_visitor<Node>{}, tpos, rpos);
- return concat_rebalance<Node>(lpos, cpos, null_sub_pos{});
- } else if (lshift < rshift) {
- auto cpos = rpos.first_sub(concat_right_visitor<Node>{}, lpos, tpos);
- return concat_rebalance<Node>(null_sub_pos{}, cpos, rpos);
- } else {
- assert(lshift == rshift);
- assert(Node::bits_leaf == 0u || lshift > 0);
- auto cpos = lpos.last_sub(concat_both_visitor<Node>{}, tpos, rpos);
- return concat_rebalance<Node>(lpos, cpos, rpos);
- }
-}
-
-template <typename Node>
-struct concat_left_visitor : visitor_base<concat_left_visitor<Node>>
-{
- using this_t = concat_left_visitor;
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_pos<Node>
- visit_inner(LPos&& lpos, TPos&& tpos, RPos&& rpos)
- {
- return concat_inners<Node>(lpos, tpos, rpos);
- }
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_pos<Node>
- visit_leaf(LPos&& lpos, TPos&& tpos, RPos&& rpos)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-template <typename Node>
-struct concat_right_visitor : visitor_base<concat_right_visitor<Node>>
-{
- using this_t = concat_right_visitor;
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_pos<Node>
- visit_inner(RPos&& rpos, LPos&& lpos, TPos&& tpos)
- {
- return concat_inners<Node>(lpos, tpos, rpos);
- }
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_pos<Node>
- visit_leaf(RPos&& rpos, LPos&& lpos, TPos&& tpos)
- {
- return concat_leafs<Node>(lpos, tpos, rpos);
- }
-};
-
-template <typename Node>
-struct concat_both_visitor : visitor_base<concat_both_visitor<Node>>
-{
- using this_t = concat_both_visitor;
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_pos<Node>
- visit_inner(LPos&& lpos, TPos&& tpos, RPos&& rpos)
- {
- return rpos.first_sub(concat_right_visitor<Node>{}, lpos, tpos);
- }
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_pos<Node>
- visit_leaf(LPos&& lpos, TPos&& tpos, RPos&& rpos)
- {
- return rpos.first_sub_leaf(concat_right_visitor<Node>{}, lpos, tpos);
- }
-};
-
-template <typename Node>
-struct concat_trees_right_visitor
- : visitor_base<concat_trees_right_visitor<Node>>
-{
- using this_t = concat_trees_right_visitor;
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_pos<Node>
- visit_node(RPos&& rpos, LPos&& lpos, TPos&& tpos)
- {
- return concat_inners<Node>(lpos, tpos, rpos);
- }
-};
-
-template <typename Node>
-struct concat_trees_left_visitor : visitor_base<concat_trees_left_visitor<Node>>
-{
- using this_t = concat_trees_left_visitor;
-
- template <typename LPos, typename TPos, typename... Args>
- static concat_center_pos<Node>
- visit_node(LPos&& lpos, TPos&& tpos, Args&&... args)
- {
- return visit_maybe_relaxed_sub(
- args..., concat_trees_right_visitor<Node>{}, lpos, tpos);
- }
-};
-
-template <typename Node>
-relaxed_pos<Node> concat_trees(Node* lroot,
- shift_t lshift,
- size_t lsize,
- Node* ltail,
- count_t ltcount,
- Node* rroot,
- shift_t rshift,
- size_t rsize)
-{
- return visit_maybe_relaxed_sub(lroot,
- lshift,
- lsize,
- concat_trees_left_visitor<Node>{},
- make_leaf_pos(ltail, ltcount),
- rroot,
- rshift,
- rsize)
- .realize();
-}
-
-template <typename Node>
-relaxed_pos<Node> concat_trees(
- Node* ltail, count_t ltcount, Node* rroot, shift_t rshift, size_t rsize)
-{
- return make_singleton_regular_sub_pos(ltail, ltcount)
- .visit(concat_trees_left_visitor<Node>{},
- empty_leaf_pos<Node>{},
- rroot,
- rshift,
- rsize)
- .realize();
-}
-
-template <typename Node>
-using concat_center_mut_pos = concat_center_pos<Node>;
-
-template <typename Node>
-struct concat_merger_mut
-{
- using node_t = Node;
- using edit_t = typename Node::edit_t;
-
- static constexpr auto B = Node::bits;
- static constexpr auto BL = Node::bits_leaf;
-
- using result_t = concat_center_pos<Node>;
-
- edit_t ec_ = {};
-
- count_t* curr_;
- count_t n_;
- result_t result_;
- count_t count_ = 0;
- node_t* candidate_ = nullptr;
- edit_t candidate_e_ = Node::memory::transience_t::noone;
-
- concat_merger_mut(edit_t ec,
- shift_t shift,
- count_t* counts,
- count_t n,
- edit_t candidate_e,
- node_t* candidate)
- : ec_{ec}
- , curr_{counts}
- , n_{n}
- , result_{shift + B, nullptr, 0}
- {
- if (candidate) {
- candidate->ensure_mutable_relaxed_e(candidate_e, ec);
- result_.nodes_[0] = candidate;
- } else {
- result_.nodes_[0] = node_t::make_inner_r_e(ec);
- }
- }
-
- node_t* to_ = {};
- count_t to_offset_ = {};
- size_t to_size_ = {};
-
- void set_candidate(edit_t candidate_e, node_t* candidate)
- {
- candidate_ = candidate;
- candidate_e_ = candidate_e;
- }
-
- void add_child(node_t* p, size_t size)
- {
- assert(size);
- ++curr_;
- auto parent = result_.nodes_[result_.count_ - 1];
- auto relaxed = parent->relaxed();
- if (count_ == branches<B>) {
- parent->relaxed()->d.count = count_;
- assert(result_.count_ < result_t::max_children);
- n_ -= branches<B>;
- if (candidate_) {
- parent = candidate_;
- parent->ensure_mutable_relaxed_e(candidate_e_, ec_);
- candidate_ = nullptr;
- } else
- parent = node_t::make_inner_r_e(ec_);
- count_ = 0;
- relaxed = parent->relaxed();
- result_.nodes_[result_.count_] = parent;
- result_.sizes_[result_.count_] = result_.sizes_[result_.count_ - 1];
- assert(result_.sizes_[result_.count_]);
- ++result_.count_;
- }
- auto idx = count_++;
- result_.sizes_[result_.count_ - 1] += size;
- assert(size);
- assert(result_.sizes_[result_.count_ - 1]);
- relaxed->d.sizes[idx] = size + (idx ? relaxed->d.sizes[idx - 1] : 0);
- assert(relaxed->d.sizes[idx]);
- parent->inner()[idx] = p;
- };
-
- template <typename Pos>
- void merge_leaf(Pos&& p, edit_t e)
- {
- auto from = p.node();
- auto from_size = p.size();
- auto from_count = p.count();
- assert(from);
- assert(from_size);
- if (!to_ && *curr_ == from_count) {
- add_child(from, from_size);
- } else {
- auto from_offset = count_t{};
- auto from_data = from->leaf();
- auto from_mutate = from->can_mutate(e);
- do {
- if (!to_) {
- if (from_mutate) {
- node_t::ownee(from) = ec_;
- to_ = from->inc();
- assert(from_count);
- } else {
- to_ = node_t::make_leaf_e(ec_);
- }
- to_offset_ = 0;
- }
- auto data = to_->leaf();
- auto to_copy =
- std::min(from_count - from_offset, *curr_ - to_offset_);
- if (from == to_) {
- if (from_offset != to_offset_)
- std::move(from_data + from_offset,
- from_data + from_offset + to_copy,
- data + to_offset_);
- } else {
- if (!from_mutate)
- detail::uninitialized_copy(from_data + from_offset,
- from_data + from_offset +
- to_copy,
- data + to_offset_);
- else
- detail::uninitialized_move(from_data + from_offset,
- from_data + from_offset +
- to_copy,
- data + to_offset_);
- }
- to_offset_ += to_copy;
- from_offset += to_copy;
- if (*curr_ == to_offset_) {
- add_child(to_, to_offset_);
- to_ = nullptr;
- }
- } while (from_offset != from_count);
- }
- }
-
- template <typename Pos>
- void merge_inner(Pos&& p, edit_t e)
- {
- auto from = p.node();
- auto from_size = p.size();
- auto from_count = p.count();
- assert(from_size);
- if (!to_ && *curr_ == from_count) {
- add_child(from, from_size);
- } else {
- auto from_offset = count_t{};
- auto from_data = from->inner();
- auto from_mutate = from->can_relax() && from->can_mutate(e);
- do {
- if (!to_) {
- if (from_mutate) {
- node_t::ownee(from) = ec_;
- from->ensure_mutable_relaxed_e(e, ec_);
- to_ = from;
- } else {
- to_ = node_t::make_inner_r_e(ec_);
- }
- to_offset_ = 0;
- to_size_ = 0;
- }
- auto data = to_->inner();
- auto to_copy =
- std::min(from_count - from_offset, *curr_ - to_offset_);
- auto sizes = to_->relaxed()->d.sizes;
- if (from != to_ || from_offset != to_offset_) {
- std::copy(from_data + from_offset,
- from_data + from_offset + to_copy,
- data + to_offset_);
- p.copy_sizes(
- from_offset, to_copy, to_size_, sizes + to_offset_);
- }
- to_offset_ += to_copy;
- from_offset += to_copy;
- to_size_ = sizes[to_offset_ - 1];
- if (*curr_ == to_offset_) {
- to_->relaxed()->d.count = to_offset_;
- add_child(to_, to_size_);
- to_ = nullptr;
- }
- } while (from_offset != from_count);
- }
- }
-
- concat_center_pos<Node> finish() const
- {
- assert(!to_);
- result_.nodes_[result_.count_ - 1]->relaxed()->d.count = count_;
- return result_;
- }
-
- void abort()
- {
- // We may have mutated stuff the tree in place, leaving
- // everything in a corrupted state... It should be possible
- // to define cleanup properly, but that is a task for some
- // other day... ;)
- std::terminate();
- }
-};
-
-struct concat_merger_mut_visitor : visitor_base<concat_merger_mut_visitor>
-{
- using this_t = concat_merger_mut_visitor;
-
- template <typename Pos, typename Merger>
- static void visit_inner(Pos&& p, Merger& merger, edit_type<Pos> e)
- {
- merger.merge_inner(p, e);
- }
-
- template <typename Pos, typename Merger>
- static void visit_leaf(Pos&& p, Merger& merger, edit_type<Pos> e)
- {
- merger.merge_leaf(p, e);
- }
-};
-
-template <bits_t B, bits_t BL>
-struct concat_rebalance_plan_mut : concat_rebalance_plan<B, BL>
-{
- using this_t = concat_rebalance_plan_mut;
-
- template <typename LPos, typename CPos, typename RPos>
- concat_center_mut_pos<node_type<CPos>> merge(edit_type<CPos> ec,
- edit_type<CPos> el,
- LPos&& lpos,
- CPos&& cpos,
- edit_type<CPos> er,
- RPos&& rpos)
- {
- using node_t = node_type<CPos>;
- using merger_t = concat_merger_mut<node_t>;
- using visitor_t = concat_merger_mut_visitor;
- auto lnode = ((node_t*) lpos.node());
- auto rnode = ((node_t*) rpos.node());
- auto lmut2 = lnode && lnode->can_relax() && lnode->can_mutate(el);
- auto rmut2 = rnode && rnode->can_relax() && rnode->can_mutate(er);
- auto merger = merger_t{ec,
- cpos.shift(),
- this->counts,
- this->n,
- el,
- lmut2 ? lnode : nullptr};
- IMMER_TRY {
- lpos.each_left_sub(visitor_t{}, merger, el);
- cpos.each_sub(visitor_t{}, merger, ec);
- if (rmut2)
- merger.set_candidate(er, rnode);
- rpos.each_right_sub(visitor_t{}, merger, er);
- return merger.finish();
- }
- IMMER_CATCH (...) {
- merger.abort();
- IMMER_RETHROW;
- }
- }
-};
-
-template <typename Node, typename LPos, typename CPos, typename RPos>
-concat_center_pos<Node> concat_rebalance_mut(edit_type<Node> ec,
- edit_type<Node> el,
- LPos&& lpos,
- CPos&& cpos,
- edit_type<Node> er,
- RPos&& rpos)
-{
- auto plan = concat_rebalance_plan_mut<Node::bits, Node::bits_leaf>{};
- plan.fill(lpos, cpos, rpos);
- plan.shuffle(cpos.shift());
- return plan.merge(ec, el, lpos, cpos, er, rpos);
-}
-
-template <typename Node, typename LPos, typename TPos, typename RPos>
-concat_center_mut_pos<Node> concat_leafs_mut(edit_type<Node> ec,
- edit_type<Node> el,
- LPos&& lpos,
- TPos&& tpos,
- edit_type<Node> er,
- RPos&& rpos)
-{
- static_assert(Node::bits >= 2, "");
- assert(lpos.shift() == tpos.shift());
- assert(lpos.shift() == rpos.shift());
- assert(lpos.shift() == 0);
- if (tpos.count() > 0)
- return {
- Node::bits_leaf,
- lpos.node(),
- lpos.count(),
- tpos.node(),
- tpos.count(),
- rpos.node(),
- rpos.count(),
- };
- else
- return {
- Node::bits_leaf,
- lpos.node(),
- lpos.count(),
- rpos.node(),
- rpos.count(),
- };
-}
-
-template <typename Node>
-struct concat_left_mut_visitor;
-template <typename Node>
-struct concat_right_mut_visitor;
-template <typename Node>
-struct concat_both_mut_visitor;
-
-template <typename Node, typename LPos, typename TPos, typename RPos>
-concat_center_mut_pos<Node> concat_inners_mut(edit_type<Node> ec,
- edit_type<Node> el,
- LPos&& lpos,
- TPos&& tpos,
- edit_type<Node> er,
- RPos&& rpos)
-{
- auto lshift = lpos.shift();
- auto rshift = rpos.shift();
- // lpos.node() can be null it is a singleton_regular_sub_pos<...>,
- // this is, when the tree is just a tail...
- if (lshift > rshift) {
- auto cpos = lpos.last_sub(
- concat_left_mut_visitor<Node>{}, ec, el, tpos, er, rpos);
- return concat_rebalance_mut<Node>(
- ec, el, lpos, cpos, er, null_sub_pos{});
- } else if (lshift < rshift) {
- auto cpos = rpos.first_sub(
- concat_right_mut_visitor<Node>{}, ec, el, lpos, tpos, er);
- return concat_rebalance_mut<Node>(
- ec, el, null_sub_pos{}, cpos, er, rpos);
- } else {
- assert(lshift == rshift);
- assert(Node::bits_leaf == 0u || lshift > 0);
- auto cpos = lpos.last_sub(
- concat_both_mut_visitor<Node>{}, ec, el, tpos, er, rpos);
- return concat_rebalance_mut<Node>(ec, el, lpos, cpos, er, rpos);
- }
-}
-
-template <typename Node>
-struct concat_left_mut_visitor : visitor_base<concat_left_mut_visitor<Node>>
-{
- using this_t = concat_left_mut_visitor;
- using edit_t = typename Node::edit_t;
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_mut_pos<Node> visit_inner(
- LPos&& lpos, edit_t ec, edit_t el, TPos&& tpos, edit_t er, RPos&& rpos)
- {
- return concat_inners_mut<Node>(ec, el, lpos, tpos, er, rpos);
- }
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_mut_pos<Node> visit_leaf(
- LPos&& lpos, edit_t ec, edit_t el, TPos&& tpos, edit_t er, RPos&& rpos)
- {
- IMMER_UNREACHABLE;
- }
-};
-
-template <typename Node>
-struct concat_right_mut_visitor : visitor_base<concat_right_mut_visitor<Node>>
-{
- using this_t = concat_right_mut_visitor;
- using edit_t = typename Node::edit_t;
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_mut_pos<Node> visit_inner(
- RPos&& rpos, edit_t ec, edit_t el, LPos&& lpos, TPos&& tpos, edit_t er)
- {
- return concat_inners_mut<Node>(ec, el, lpos, tpos, er, rpos);
- }
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_mut_pos<Node> visit_leaf(
- RPos&& rpos, edit_t ec, edit_t el, LPos&& lpos, TPos&& tpos, edit_t er)
- {
- return concat_leafs_mut<Node>(ec, el, lpos, tpos, er, rpos);
- }
-};
-
-template <typename Node>
-struct concat_both_mut_visitor : visitor_base<concat_both_mut_visitor<Node>>
-{
- using this_t = concat_both_mut_visitor;
- using edit_t = typename Node::edit_t;
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_mut_pos<Node> visit_inner(
- LPos&& lpos, edit_t ec, edit_t el, TPos&& tpos, edit_t er, RPos&& rpos)
- {
- return rpos.first_sub(
- concat_right_mut_visitor<Node>{}, ec, el, lpos, tpos, er);
- }
-
- template <typename LPos, typename TPos, typename RPos>
- static concat_center_mut_pos<Node> visit_leaf(
- LPos&& lpos, edit_t ec, edit_t el, TPos&& tpos, edit_t er, RPos&& rpos)
- {
- return rpos.first_sub_leaf(
- concat_right_mut_visitor<Node>{}, ec, el, lpos, tpos, er);
- }
-};
-
-template <typename Node>
-struct concat_trees_right_mut_visitor
- : visitor_base<concat_trees_right_mut_visitor<Node>>
-{
- using this_t = concat_trees_right_mut_visitor;
- using edit_t = typename Node::edit_t;
-
- template <typename RPos, typename LPos, typename TPos>
- static concat_center_mut_pos<Node> visit_node(
- RPos&& rpos, edit_t ec, edit_t el, LPos&& lpos, TPos&& tpos, edit_t er)
- {
- return concat_inners_mut<Node>(ec, el, lpos, tpos, er, rpos);
- }
-};
-
-template <typename Node>
-struct concat_trees_left_mut_visitor
- : visitor_base<concat_trees_left_mut_visitor<Node>>
-{
- using this_t = concat_trees_left_mut_visitor;
- using edit_t = typename Node::edit_t;
-
- template <typename LPos, typename TPos, typename... Args>
- static concat_center_mut_pos<Node> visit_node(LPos&& lpos,
- edit_t ec,
- edit_t el,
- TPos&& tpos,
- edit_t er,
- Args&&... args)
- {
- return visit_maybe_relaxed_sub(args...,
- concat_trees_right_mut_visitor<Node>{},
- ec,
- el,
- lpos,
- tpos,
- er);
- }
-};
-
-template <typename Node>
-relaxed_pos<Node> concat_trees_mut(edit_type<Node> ec,
- edit_type<Node> el,
- Node* lroot,
- shift_t lshift,
- size_t lsize,
- Node* ltail,
- count_t ltcount,
- edit_type<Node> er,
- Node* rroot,
- shift_t rshift,
- size_t rsize)
-{
- return visit_maybe_relaxed_sub(lroot,
- lshift,
- lsize,
- concat_trees_left_mut_visitor<Node>{},
- ec,
- el,
- make_leaf_pos(ltail, ltcount),
- er,
- rroot,
- rshift,
- rsize)
- .realize_e(ec);
-}
-
-template <typename Node>
-relaxed_pos<Node> concat_trees_mut(edit_type<Node> ec,
- edit_type<Node> el,
- Node* ltail,
- count_t ltcount,
- edit_type<Node> er,
- Node* rroot,
- shift_t rshift,
- size_t rsize)
-{
- return make_singleton_regular_sub_pos(ltail, ltcount)
- .visit(concat_trees_left_mut_visitor<Node>{},
- ec,
- el,
- empty_leaf_pos<Node>{},
- er,
- rroot,
- rshift,
- rsize)
- .realize_e(ec);
-}
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/position.hpp b/src/third_party/immer/dist/immer/detail/rbts/position.hpp
deleted file mode 100644
index cbdd1c2f1f4..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/position.hpp
+++ /dev/null
@@ -1,1994 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/rbts/bits.hpp>
-
-#include <cassert>
-#include <type_traits>
-#include <utility>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename Pos>
-constexpr auto bits = std::decay_t<Pos>::node_t::bits;
-
-template <typename Pos>
-constexpr auto bits_leaf = std::decay_t<Pos>::node_t::bits_leaf;
-
-template <typename Pos>
-using node_type = typename std::decay<Pos>::type::node_t;
-
-template <typename Pos>
-using edit_type = typename std::decay<Pos>::type::node_t::edit_t;
-
-template <typename NodeT>
-struct empty_regular_pos
-{
- using node_t = NodeT;
- node_t* node_;
-
- count_t count() const { return 0; }
- node_t* node() const { return node_; }
- shift_t shift() const { return 0; }
- size_t size() const { return 0; }
-
- template <typename Visitor, typename... Args>
- void each(Visitor, Args&&...)
- {}
- template <typename Visitor, typename... Args>
- bool each_pred(Visitor, Args&&...)
- {
- return true;
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-empty_regular_pos<NodeT> make_empty_regular_pos(NodeT* node)
-{
- return {node};
-}
-
-template <typename NodeT>
-struct empty_leaf_pos
-{
- using node_t = NodeT;
- node_t* node_;
-
- count_t count() const { return 0; }
- node_t* node() const { return node_; }
- shift_t shift() const { return 0; }
- size_t size() const { return 0; }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-empty_leaf_pos<NodeT> make_empty_leaf_pos(NodeT* node)
-{
- assert(node);
- return {node};
-}
-
-template <typename NodeT>
-struct leaf_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
- size_t size_;
-
- count_t count() const { return index(size_ - 1) + 1; }
- node_t* node() const { return node_; }
- size_t size() const { return size_; }
- shift_t shift() const { return 0; }
- count_t index(size_t idx) const { return idx & mask<BL>; }
- count_t subindex(size_t idx) const { return idx; }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-leaf_pos<NodeT> make_leaf_pos(NodeT* node, size_t size)
-{
- assert(node);
- assert(size > 0);
- return {node, size};
-}
-
-template <typename NodeT>
-struct leaf_sub_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
- count_t count_;
-
- count_t count() const { return count_; }
- node_t* node() const { return node_; }
- size_t size() const { return count_; }
- shift_t shift() const { return 0; }
- count_t index(size_t idx) const { return idx & mask<BL>; }
- count_t subindex(size_t idx) const { return idx; }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-leaf_sub_pos<NodeT> make_leaf_sub_pos(NodeT* node, count_t count)
-{
- assert(node);
- assert(count <= branches<NodeT::bits_leaf>);
- return {node, count};
-}
-
-template <typename NodeT>
-struct leaf_descent_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
-
- node_t* node() const { return node_; }
- shift_t shift() const { return 0; }
- count_t index(size_t idx) const { return idx & mask<BL>; }
-
- template <typename... Args>
- decltype(auto) descend(Args&&...)
- {}
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-leaf_descent_pos<NodeT> make_leaf_descent_pos(NodeT* node)
-{
- assert(node);
- return {node};
-}
-
-template <typename NodeT>
-struct full_leaf_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
-
- count_t count() const { return branches<BL>; }
- node_t* node() const { return node_; }
- size_t size() const { return branches<BL>; }
- shift_t shift() const { return 0; }
- count_t index(size_t idx) const { return idx & mask<BL>; }
- count_t subindex(size_t idx) const { return idx; }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_leaf(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-full_leaf_pos<NodeT> make_full_leaf_pos(NodeT* node)
-{
- assert(node);
- return {node};
-}
-
-template <typename NodeT>
-struct regular_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
- shift_t shift_;
- size_t size_;
-
- count_t count() const { return index(size_ - 1) + 1; }
- node_t* node() const { return node_; }
- size_t size() const { return size_; }
- shift_t shift() const { return shift_; }
- count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
- count_t subindex(size_t idx) const { return idx >> shift_; }
- size_t this_size() const
- {
- return ((size_ - 1) & ~(~size_t{} << (shift_ + B))) + 1;
- }
-
- template <typename Visitor, typename... Args>
- void each(Visitor v, Args&&... args)
- {
- return each_regular(*this, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred(Visitor v, Args&&... args)
- {
- return each_pred_regular(*this, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
- {
- return each_pred_zip_regular(*this, v, other, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- return each_pred_i_regular(*this, v, i, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_right(Visitor v, count_t start, Args&&... args)
- {
- return each_pred_right_regular(*this, v, start, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_left(Visitor v, count_t n, Args&&... args)
- {
- return each_pred_left_regular(*this, v, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- return each_i_regular(*this, v, i, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right(Visitor v, count_t start, Args&&... args)
- {
- return each_right_regular(*this, v, start, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left(Visitor v, count_t n, Args&&... args)
- {
- return each_left_regular(*this, v, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, index(idx), count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, offset_hint, count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards_oh_ch(Visitor v,
- size_t idx,
- count_t offset_hint,
- count_t count_hint,
- Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, offset_hint, count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- return towards_sub_oh_regular(*this, v, idx, offset_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args)
- {
- return last_oh_regular(*this, v, offset_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename Pos, typename Visitor, typename... Args>
-void each_regular(Pos&& p, Visitor v, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- auto n = p.node()->inner();
- auto last = p.count() - 1;
- auto e = n + last;
- if (p.shift() == BL) {
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- make_leaf_pos(*n, p.size()).visit(v, args...);
- } else {
- auto ss = p.shift() - B;
- for (; n != e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- make_regular_pos(*n, ss, p.size()).visit(v, args...);
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-bool each_pred_regular(Pos&& p, Visitor v, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- auto n = p.node()->inner();
- auto last = p.count() - 1;
- auto e = n + last;
- if (p.shift() == BL) {
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- if (!make_full_leaf_pos(*n).visit(v, args...))
- return false;
- }
- return make_leaf_pos(*n, p.size()).visit(v, args...);
- } else {
- auto ss = p.shift() - B;
- for (; n != e; ++n)
- if (!make_full_pos(*n, ss).visit(v, args...))
- return false;
- return make_regular_pos(*n, ss, p.size()).visit(v, args...);
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-bool each_pred_zip_regular(Pos&& p,
- Visitor v,
- node_type<Pos>* other,
- Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
-
- auto n = p.node()->inner();
- auto n2 = other->inner();
- auto last = p.count() - 1;
- auto e = n + last;
- if (p.shift() == BL) {
- for (; n != e; ++n, ++n2) {
- IMMER_PREFETCH(n + 1);
- IMMER_PREFETCH(n2 + 1);
- if (!make_full_leaf_pos(*n).visit(v, *n2, args...))
- return false;
- }
- return make_leaf_pos(*n, p.size()).visit(v, *n2, args...);
- } else {
- auto ss = p.shift() - B;
- for (; n != e; ++n, ++n2)
- if (!make_full_pos(*n, ss).visit(v, *n2, args...))
- return false;
- return make_regular_pos(*n, ss, p.size()).visit(v, *n2, args...);
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-bool each_pred_i_regular(
- Pos&& p, Visitor v, count_t f, count_t l, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
-
- if (p.shift() == BL) {
- if (l > f) {
- if (l < p.count()) {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l;
- for (; n < e; ++n) {
- IMMER_PREFETCH(n + 1);
- if (!make_full_leaf_pos(*n).visit(v, args...))
- return false;
- }
- } else {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l - 1;
- for (; n < e; ++n) {
- IMMER_PREFETCH(n + 1);
- if (!make_full_leaf_pos(*n).visit(v, args...))
- return false;
- }
- if (!make_leaf_pos(*n, p.size()).visit(v, args...))
- return false;
- }
- }
- } else {
- if (l > f) {
- auto ss = p.shift() - B;
- if (l < p.count()) {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l;
- for (; n < e; ++n)
- if (!make_full_pos(*n, ss).visit(v, args...))
- return false;
- } else {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l - 1;
- for (; n < e; ++n)
- if (!make_full_pos(*n, ss).visit(v, args...))
- return false;
- if (!make_regular_pos(*n, ss, p.size()).visit(v, args...))
- return false;
- }
- }
- }
- return true;
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-bool each_pred_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- assert(last < p.count());
- if (p.shift() == BL) {
- auto n = p.node()->inner();
- auto e = n + last;
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- if (!make_full_leaf_pos(*n).visit(v, args...))
- return false;
- }
- } else {
- auto n = p.node()->inner();
- auto e = n + last;
- auto ss = p.shift() - B;
- for (; n != e; ++n)
- if (!make_full_pos(*n, ss).visit(v, args...))
- return false;
- }
- return true;
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-bool each_pred_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
-
- if (p.shift() == BL) {
- auto n = p.node()->inner() + start;
- auto last = p.count() - 1;
- auto e = p.node()->inner() + last;
- if (n <= e) {
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- if (!make_full_leaf_pos(*n).visit(v, args...))
- return false;
- }
- if (!make_leaf_pos(*n, p.size()).visit(v, args...))
- return false;
- }
- } else {
- auto n = p.node()->inner() + start;
- auto last = p.count() - 1;
- auto e = p.node()->inner() + last;
- auto ss = p.shift() - B;
- if (n <= e) {
- for (; n != e; ++n)
- if (!make_full_pos(*n, ss).visit(v, args...))
- return false;
- if (!make_regular_pos(*n, ss, p.size()).visit(v, args...))
- return false;
- }
- }
- return true;
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-void each_i_regular(Pos&& p, Visitor v, count_t f, count_t l, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
-
- if (p.shift() == BL) {
- if (l > f) {
- if (l < p.count()) {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l;
- for (; n < e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- } else {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l - 1;
- for (; n < e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- make_leaf_pos(*n, p.size()).visit(v, args...);
- }
- }
- } else {
- if (l > f) {
- auto ss = p.shift() - B;
- if (l < p.count()) {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l;
- for (; n < e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- } else {
- auto n = p.node()->inner() + f;
- auto e = p.node()->inner() + l - 1;
- for (; n < e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- make_regular_pos(*n, ss, p.size()).visit(v, args...);
- }
- }
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-void each_left_regular(Pos&& p, Visitor v, count_t last, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- assert(last < p.count());
- if (p.shift() == BL) {
- auto n = p.node()->inner();
- auto e = n + last;
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- } else {
- auto n = p.node()->inner();
- auto e = n + last;
- auto ss = p.shift() - B;
- for (; n != e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-void each_right_regular(Pos&& p, Visitor v, count_t start, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
-
- if (p.shift() == BL) {
- auto n = p.node()->inner() + start;
- auto last = p.count() - 1;
- auto e = p.node()->inner() + last;
- if (n <= e) {
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- make_leaf_pos(*n, p.size()).visit(v, args...);
- }
- } else {
- auto n = p.node()->inner() + start;
- auto last = p.count() - 1;
- auto e = p.node()->inner() + last;
- auto ss = p.shift() - B;
- if (n <= e) {
- for (; n != e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- make_regular_pos(*n, ss, p.size()).visit(v, args...);
- }
- }
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-decltype(auto) towards_oh_ch_regular(Pos&& p,
- Visitor v,
- size_t idx,
- count_t offset_hint,
- count_t count_hint,
- Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- assert(offset_hint == p.index(idx));
- assert(count_hint == p.count());
- auto is_leaf = p.shift() == BL;
- auto child = p.node()->inner()[offset_hint];
- auto is_full = offset_hint + 1 != count_hint;
- return is_full
- ? (is_leaf ? make_full_leaf_pos(child).visit(v, idx, args...)
- : make_full_pos(child, p.shift() - B)
- .visit(v, idx, args...))
- : (is_leaf
- ? make_leaf_pos(child, p.size()).visit(v, idx, args...)
- : make_regular_pos(child, p.shift() - B, p.size())
- .visit(v, idx, args...));
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-decltype(auto) towards_sub_oh_regular(
- Pos&& p, Visitor v, size_t idx, count_t offset_hint, Args&&... args)
-{
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- assert(offset_hint == p.index(idx));
- auto is_leaf = p.shift() == BL;
- auto child = p.node()->inner()[offset_hint];
- auto lsize = offset_hint << p.shift();
- auto size = p.this_size();
- auto is_full = (size - lsize) >= (size_t{1} << p.shift());
- return is_full
- ? (is_leaf
- ? make_full_leaf_pos(child).visit(v, idx - lsize, args...)
- : make_full_pos(child, p.shift() - B)
- .visit(v, idx - lsize, args...))
- : (is_leaf
- ? make_leaf_sub_pos(child, size - lsize)
- .visit(v, idx - lsize, args...)
- : make_regular_sub_pos(child, p.shift() - B, size - lsize)
- .visit(v, idx - lsize, args...));
-}
-
-template <typename Pos, typename Visitor, typename... Args>
-decltype(auto)
-last_oh_regular(Pos&& p, Visitor v, count_t offset_hint, Args&&... args)
-{
- assert(offset_hint == p.count() - 1);
- constexpr auto B = bits<Pos>;
- constexpr auto BL = bits_leaf<Pos>;
- auto child = p.node()->inner()[offset_hint];
- auto is_leaf = p.shift() == BL;
- return is_leaf ? make_leaf_pos(child, p.size()).visit(v, args...)
- : make_regular_pos(child, p.shift() - B, p.size())
- .visit(v, args...);
-}
-
-template <typename NodeT>
-regular_pos<NodeT> make_regular_pos(NodeT* node, shift_t shift, size_t size)
-{
- assert(node);
- assert(shift >= NodeT::bits_leaf);
- assert(size > 0);
- return {node, shift, size};
-}
-
-struct null_sub_pos
-{
- auto node() const { return nullptr; }
-
- template <typename Visitor, typename... Args>
- void each_sub(Visitor, Args&&...)
- {}
- template <typename Visitor, typename... Args>
- void each_right_sub(Visitor, Args&&...)
- {}
- template <typename Visitor, typename... Args>
- void each_left_sub(Visitor, Args&&...)
- {}
- template <typename Visitor, typename... Args>
- void visit(Visitor, Args&&...)
- {}
-};
-
-template <typename NodeT>
-struct singleton_regular_sub_pos
-{
- // this is a fake regular pos made out of a single child... useful
- // to treat a single leaf node as a whole tree
-
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* leaf_;
- count_t count_;
-
- count_t count() const { return 1; }
- node_t* node() const { return nullptr; }
- size_t size() const { return count_; }
- shift_t shift() const { return BL; }
- count_t index(size_t idx) const { return 0; }
- count_t subindex(size_t idx) const { return 0; }
- size_t size_before(count_t offset) const { return 0; }
- size_t this_size() const { return count_; }
- size_t size(count_t offset) { return count_; }
-
- template <typename Visitor, typename... Args>
- void each_left_sub(Visitor v, Args&&... args)
- {}
- template <typename Visitor, typename... Args>
- void each(Visitor v, Args&&... args)
- {}
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_sub(Visitor v, Args&&... args)
- {
- return make_leaf_sub_pos(leaf_, count_).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-auto make_singleton_regular_sub_pos(NodeT* leaf, count_t count)
-{
- assert(leaf);
- IMMER_ASSERT_TAGGED(leaf->kind() == NodeT::kind_t::leaf);
- assert(count > 0);
- return singleton_regular_sub_pos<NodeT>{leaf, count};
-}
-
-template <typename NodeT>
-struct regular_sub_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
- shift_t shift_;
- size_t size_;
-
- count_t count() const { return subindex(size_ - 1) + 1; }
- node_t* node() const { return node_; }
- size_t size() const { return size_; }
- shift_t shift() const { return shift_; }
- count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
- count_t subindex(size_t idx) const { return idx >> shift_; }
- size_t size_before(count_t offset) const
- {
- return size_t{offset} << shift_;
- }
- size_t this_size() const { return size_; }
-
- auto size(count_t offset)
- {
- return offset == subindex(size_ - 1) ? size_ - size_before(offset)
- : size_t{1} << shift_;
- }
-
- auto size_sbh(count_t offset, size_t size_before_hint)
- {
- assert(size_before_hint == size_before(offset));
- return offset == subindex(size_ - 1) ? size_ - size_before_hint
- : size_t{1} << shift_;
- }
-
- void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
- {
- if (n) {
- auto last = offset + n - 1;
- auto e = sizes + n - 1;
- for (; sizes != e; ++sizes) {
- init = *sizes = init + (size_t{1} << shift_);
- assert(init);
- }
- *sizes = init + size(last);
- assert(*sizes);
- }
- }
-
- template <typename Visitor, typename... Args>
- void each(Visitor v, Args&&... args)
- {
- return each_regular(*this, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred(Visitor v, Args&&... args)
- {
- return each_pred_regular(*this, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
- {
- return each_pred_zip_regular(*this, v, other, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- return each_pred_i_regular(*this, v, i, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_right(Visitor v, count_t start, Args&&... args)
- {
- return each_pred_right_regular(*this, v, start, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_left(Visitor v, count_t last, Args&&... args)
- {
- return each_pred_left_regular(*this, v, last, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- return each_i_regular(*this, v, i, n, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right(Visitor v, count_t start, Args&&... args)
- {
- return each_right_regular(*this, v, start, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left(Visitor v, count_t last, Args&&... args)
- {
- return each_left_regular(*this, v, last, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right_sub_(Visitor v, count_t i, Args&&... args)
- {
- auto last = count() - 1;
- auto lsize = size_ - (last << shift_);
- auto n = node()->inner() + i;
- auto e = node()->inner() + last;
- if (shift() == BL) {
- for (; n != e; ++n) {
- IMMER_PREFETCH(n + 1);
- make_full_leaf_pos(*n).visit(v, args...);
- }
- make_leaf_sub_pos(*n, lsize).visit(v, args...);
- } else {
- auto ss = shift_ - B;
- for (; n != e; ++n)
- make_full_pos(*n, ss).visit(v, args...);
- make_regular_sub_pos(*n, ss, lsize).visit(v, args...);
- }
- }
-
- template <typename Visitor, typename... Args>
- void each_sub(Visitor v, Args&&... args)
- {
- each_right_sub_(v, 0, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right_sub(Visitor v, Args&&... args)
- {
- if (count() > 1)
- each_right_sub_(v, 1, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left_sub(Visitor v, Args&&... args)
- {
- each_left(v, count() - 1, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, index(idx), count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, offset_hint, count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards_oh_ch(Visitor v,
- size_t idx,
- count_t offset_hint,
- count_t count_hint,
- Args&&... args)
- {
- return towards_oh_ch_regular(
- *this, v, idx, offset_hint, count(), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- return towards_sub_oh_regular(*this, v, idx, offset_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_oh(Visitor v, count_t offset_hint, Args&&... args)
- {
- return last_oh_regular(*this, v, offset_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_sub(Visitor v, Args&&... args)
- {
- auto offset = count() - 1;
- auto child = node_->inner()[offset];
- auto is_leaf = shift_ == BL;
- auto lsize = size_ - (size_t{offset} << shift_);
- return is_leaf ? make_leaf_sub_pos(child, lsize).visit(v, args...)
- : make_regular_sub_pos(child, shift_ - B, lsize)
- .visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub(Visitor v, Args&&... args)
- {
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[0];
- auto is_full = size_ >= (size_t{1} << shift_);
- return is_full
- ? (is_leaf
- ? make_full_leaf_pos(child).visit(v, args...)
- : make_full_pos(child, shift_ - B).visit(v, args...))
- : (is_leaf
- ? make_leaf_sub_pos(child, size_).visit(v, args...)
- : make_regular_sub_pos(child, shift_ - B, size_)
- .visit(v, args...));
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- auto child = node_->inner()[0];
- auto is_full = size_ >= branches<BL>;
- return is_full ? make_full_leaf_pos(child).visit(v, args...)
- : make_leaf_sub_pos(child, size_).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_inner(Visitor v, Args&&... args)
- {
- assert(shift_ >= BL);
- auto child = node_->inner()[0];
- auto is_full = size_ >= branches<BL>;
- return is_full ? make_full_pos(child, shift_ - B).visit(v, args...)
- : make_regular_sub_pos(child, shift_ - B, size_)
- .visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub(count_t idx, Visitor v, Args&&... args)
- {
- assert(idx < count());
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[idx];
- auto lsize = size(idx);
- auto is_full = idx + 1 < count();
- return is_full
- ? (is_leaf
- ? make_full_leaf_pos(child).visit(v, args...)
- : make_full_pos(child, shift_ - B).visit(v, args...))
- : (is_leaf
- ? make_leaf_sub_pos(child, lsize).visit(v, args...)
- : make_regular_sub_pos(child, shift_ - B, lsize)
- .visit(v, args...));
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub_leaf(count_t idx, Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- auto child = node_->inner()[idx];
- auto lsize = size(idx);
- auto is_full = idx + 1 < count();
- return is_full ? make_full_leaf_pos(child).visit(v, args...)
- : make_leaf_sub_pos(child, lsize).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-regular_sub_pos<NodeT>
-make_regular_sub_pos(NodeT* node, shift_t shift, size_t size)
-{
- assert(node);
- assert(shift >= NodeT::bits_leaf);
- assert(size > 0);
- assert(size <= (branches<NodeT::bits, size_t> << shift));
- return {node, shift, size};
-}
-
-template <typename NodeT,
- shift_t Shift,
- bits_t B = NodeT::bits,
- bits_t BL = NodeT::bits_leaf>
-struct regular_descent_pos
-{
- static_assert(Shift > 0, "not leaf...");
-
- using node_t = NodeT;
- node_t* node_;
-
- node_t* node() const { return node_; }
- shift_t shift() const { return Shift; }
- count_t index(size_t idx) const
- {
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshift-count-overflow"
-#endif
- return (idx >> Shift) & mask<B>;
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic pop
-#endif
- }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx)
- {
- auto offset = index(idx);
- auto child = node_->inner()[offset];
- return regular_descent_pos<NodeT, Shift - B>{child}.visit(v, idx);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT, bits_t B, bits_t BL>
-struct regular_descent_pos<NodeT, BL, B, BL>
-{
- using node_t = NodeT;
- node_t* node_;
-
- node_t* node() const { return node_; }
- shift_t shift() const { return BL; }
- count_t index(size_t idx) const { return (idx >> BL) & mask<B>; }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx)
- {
- auto offset = index(idx);
- auto child = node_->inner()[offset];
- return make_leaf_descent_pos(child).visit(v, idx);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT, typename Visitor>
-decltype(auto)
-visit_regular_descent(NodeT* node, shift_t shift, Visitor v, size_t idx)
-{
- constexpr auto B = NodeT::bits;
- constexpr auto BL = NodeT::bits_leaf;
- assert(node);
- assert(shift >= BL);
- switch (shift) {
- case BL + B * 0:
- return regular_descent_pos<NodeT, BL + B * 0>{node}.visit(v, idx);
- case BL + B * 1:
- return regular_descent_pos<NodeT, BL + B * 1>{node}.visit(v, idx);
- case BL + B * 2:
- return regular_descent_pos<NodeT, BL + B * 2>{node}.visit(v, idx);
- case BL + B * 3:
- return regular_descent_pos<NodeT, BL + B * 3>{node}.visit(v, idx);
- case BL + B * 4:
- return regular_descent_pos<NodeT, BL + B * 4>{node}.visit(v, idx);
- case BL + B * 5:
- return regular_descent_pos<NodeT, BL + B * 5>{node}.visit(v, idx);
-#if IMMER_DESCENT_DEEP
- default:
- for (auto level = shift; level != endshift<B, BL>; level -= B)
- node = node->inner()[(idx >> level) & mask<B>];
- return make_leaf_descent_pos(node).visit(v, idx);
-#endif // IMMER_DEEP_DESCENT
- }
- IMMER_UNREACHABLE;
-}
-
-template <typename NodeT>
-struct full_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- node_t* node_;
- shift_t shift_;
-
- count_t count() const { return branches<B>; }
- node_t* node() const { return node_; }
- size_t size() const { return branches<B, size_t> << shift_; }
- shift_t shift() const { return shift_; }
- count_t index(size_t idx) const { return (idx >> shift_) & mask<B>; }
- count_t subindex(size_t idx) const { return idx >> shift_; }
- size_t size(count_t offset) const { return size_t{1} << shift_; }
- size_t size_sbh(count_t offset, size_t) const
- {
- return size_t{1} << shift_;
- }
- size_t size_before(count_t offset) const
- {
- return size_t{offset} << shift_;
- }
-
- void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
- {
- auto e = sizes + n;
- for (; sizes != e; ++sizes) {
- init = *sizes = init + (size_t{1} << shift_);
- assert(init);
- }
- }
-
- template <typename Visitor, typename... Args>
- void each(Visitor v, Args&&... args)
- {
- auto p = node_->inner();
- auto e = p + branches<B>;
- if (shift_ == BL) {
- for (; p != e; ++p) {
- IMMER_PREFETCH(p + 1);
- make_full_leaf_pos(*p).visit(v, args...);
- }
- } else {
- auto ss = shift_ - B;
- for (; p != e; ++p)
- make_full_pos(*p, ss).visit(v, args...);
- }
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred(Visitor v, Args&&... args)
- {
- auto p = node_->inner();
- auto e = p + branches<B>;
- if (shift_ == BL) {
- for (; p != e; ++p) {
- IMMER_PREFETCH(p + 1);
- if (!make_full_leaf_pos(*p).visit(v, args...))
- return false;
- }
- } else {
- auto ss = shift_ - B;
- for (; p != e; ++p)
- if (!make_full_pos(*p, ss).visit(v, args...))
- return false;
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_zip(Visitor v, node_t* other, Args&&... args)
- {
- auto p = node_->inner();
- auto p2 = other->inner();
- auto e = p + branches<B>;
- if (shift_ == BL) {
- for (; p != e; ++p, ++p2) {
- IMMER_PREFETCH(p + 1);
- if (!make_full_leaf_pos(*p).visit(v, *p2, args...))
- return false;
- }
- } else {
- auto ss = shift_ - B;
- for (; p != e; ++p, ++p2)
- if (!make_full_pos(*p, ss).visit(v, *p2, args...))
- return false;
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- auto p = node_->inner() + i;
- auto e = node_->inner() + n;
- if (shift_ == BL) {
- for (; p != e; ++p) {
- IMMER_PREFETCH(p + 1);
- if (!make_full_leaf_pos(*p).visit(v, args...))
- return false;
- }
- } else {
- auto ss = shift_ - B;
- for (; p != e; ++p)
- if (!make_full_pos(*p, ss).visit(v, args...))
- return false;
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- void each_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- auto p = node_->inner() + i;
- auto e = node_->inner() + n;
- if (shift_ == BL) {
- for (; p != e; ++p) {
- IMMER_PREFETCH(p + 1);
- make_full_leaf_pos(*p).visit(v, args...);
- }
- } else {
- auto ss = shift_ - B;
- for (; p != e; ++p)
- make_full_pos(*p, ss).visit(v, args...);
- }
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_right(Visitor v, count_t start, Args&&... args)
- {
- return each_pred_i(v, start, branches<B>, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_left(Visitor v, count_t last, Args&&... args)
- {
- return each_pred_i(v, 0, last, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_sub(Visitor v, Args&&... args)
- {
- each(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left_sub(Visitor v, Args&&... args)
- {
- each_i(v, 0, branches<B> - 1, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right_sub(Visitor v, Args&&... args)
- {
- each_i(v, 1, branches<B>, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right(Visitor v, count_t start, Args&&... args)
- {
- each_i(v, start, branches<B>, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left(Visitor v, count_t last, Args&&... args)
- {
- each_i(v, 0, last, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
- {
- return towards_oh(v, idx, index(idx), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards_oh_ch(
- Visitor v, size_t idx, count_t offset_hint, count_t, Args&&... args)
- {
- return towards_oh(v, idx, offset_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- assert(offset_hint == index(idx));
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[offset_hint];
- return is_leaf
- ? make_full_leaf_pos(child).visit(v, idx, args...)
- : make_full_pos(child, shift_ - B).visit(v, idx, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- assert(offset_hint == index(idx));
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[offset_hint];
- auto lsize = size_t{offset_hint} << shift_;
- return is_leaf
- ? make_full_leaf_pos(child).visit(v, idx - lsize, args...)
- : make_full_pos(child, shift_ - B)
- .visit(v, idx - lsize, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub(Visitor v, Args&&... args)
- {
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[0];
- return is_leaf ? make_full_leaf_pos(child).visit(v, args...)
- : make_full_pos(child, shift_ - B).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- auto child = node_->inner()[0];
- return make_full_leaf_pos(child).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_inner(Visitor v, Args&&... args)
- {
- assert(shift_ >= BL);
- auto child = node_->inner()[0];
- return make_full_pos(child, shift_ - B).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub(count_t idx, Visitor v, Args&&... args)
- {
- assert(idx < count());
- auto is_leaf = shift_ == BL;
- auto child = node_->inner()[idx];
- return is_leaf ? make_full_leaf_pos(child).visit(v, args...)
- : make_full_pos(child, shift_ - B).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub_leaf(count_t idx, Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- assert(idx < count());
- auto child = node_->inner()[idx];
- return make_full_leaf_pos(child).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_regular(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT>
-full_pos<NodeT> make_full_pos(NodeT* node, shift_t shift)
-{
- assert(node);
- assert(shift >= NodeT::bits_leaf);
- return {node, shift};
-}
-
-template <typename NodeT>
-struct relaxed_pos
-{
- static constexpr auto B = NodeT::bits;
- static constexpr auto BL = NodeT::bits_leaf;
-
- using node_t = NodeT;
- using relaxed_t = typename NodeT::relaxed_t;
- node_t* node_;
- shift_t shift_;
- relaxed_t* relaxed_;
-
- count_t count() const { return relaxed_->d.count; }
- node_t* node() const { return node_; }
- size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
- shift_t shift() const { return shift_; }
- count_t subindex(size_t idx) const { return index(idx); }
- relaxed_t* relaxed() const { return relaxed_; }
-
- size_t size_before(count_t offset) const
- {
- return offset ? relaxed_->d.sizes[offset - 1] : 0;
- }
-
- size_t size(count_t offset) const
- {
- return size_sbh(offset, size_before(offset));
- }
-
- size_t size_sbh(count_t offset, size_t size_before_hint) const
- {
- assert(size_before_hint == size_before(offset));
- return relaxed_->d.sizes[offset] - size_before_hint;
- }
-
- count_t index(size_t idx) const
- {
- auto offset = idx >> shift_;
- while (relaxed_->d.sizes[offset] <= idx)
- ++offset;
- return offset;
- }
-
- void copy_sizes(count_t offset, count_t n, size_t init, size_t* sizes)
- {
- auto e = sizes + n;
- auto prev = size_before(offset);
- auto these = relaxed_->d.sizes + offset;
- for (; sizes != e; ++sizes, ++these) {
- auto this_size = *these;
- init = *sizes = init + (this_size - prev);
- assert(init);
- prev = this_size;
- }
- }
-
- template <typename Visitor, typename... Args>
- void each(Visitor v, Args&&... args)
- {
- each_left(v, relaxed_->d.count, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred(Visitor v, Args&&... args)
- {
- auto p = node_->inner();
- auto s = size_t{};
- auto n = count();
- if (shift_ == BL) {
- for (auto i = count_t{0}; i < n; ++i) {
- IMMER_PREFETCH(p + i + 1);
- if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- } else {
- auto ss = shift_ - B;
- for (auto i = count_t{0}; i < n; ++i) {
- if (!visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- if (shift_ == BL) {
- auto p = node_->inner();
- auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
- for (; i < n; ++i) {
- IMMER_PREFETCH(p + i + 1);
- if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- } else {
- auto p = node_->inner();
- auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
- auto ss = shift_ - B;
- for (; i < n; ++i) {
- if (!visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_left(Visitor v, count_t n, Args&&... args)
- {
- auto p = node_->inner();
- auto s = size_t{};
- if (shift_ == BL) {
- for (auto i = count_t{0}; i < n; ++i) {
- IMMER_PREFETCH(p + i + 1);
- if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- } else {
- auto ss = shift_ - B;
- for (auto i = count_t{0}; i < n; ++i) {
- if (!visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- bool each_pred_right(Visitor v, count_t start, Args&&... args)
- {
- assert(start > 0);
- assert(start <= relaxed_->d.count);
- auto s = relaxed_->d.sizes[start - 1];
- auto p = node_->inner();
- if (shift_ == BL) {
- for (auto i = start; i < relaxed_->d.count; ++i) {
- IMMER_PREFETCH(p + i + 1);
- if (!make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- } else {
- auto ss = shift_ - B;
- for (auto i = start; i < relaxed_->d.count; ++i) {
- if (!visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...))
- return false;
- s = relaxed_->d.sizes[i];
- }
- }
- return true;
- }
-
- template <typename Visitor, typename... Args>
- void each_i(Visitor v, count_t i, count_t n, Args&&... args)
- {
- if (shift_ == BL) {
- auto p = node_->inner();
- auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
- for (; i < n; ++i) {
- IMMER_PREFETCH(p + i + 1);
- make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...);
- s = relaxed_->d.sizes[i];
- }
- } else {
- auto p = node_->inner();
- auto s = i > 0 ? relaxed_->d.sizes[i - 1] : 0;
- auto ss = shift_ - B;
- for (; i < n; ++i) {
- visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
- s = relaxed_->d.sizes[i];
- }
- }
- }
-
- template <typename Visitor, typename... Args>
- void each_sub(Visitor v, Args&&... args)
- {
- each_left(v, relaxed_->d.count, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left_sub(Visitor v, Args&&... args)
- {
- each_left(v, relaxed_->d.count - 1, args...);
- }
-
- template <typename Visitor, typename... Args>
- void each_left(Visitor v, count_t n, Args&&... args)
- {
- auto p = node_->inner();
- auto s = size_t{};
- if (shift_ == BL) {
- for (auto i = count_t{0}; i < n; ++i) {
- IMMER_PREFETCH(p + i + 1);
- make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...);
- s = relaxed_->d.sizes[i];
- assert(s);
- }
- } else {
- auto ss = shift_ - B;
- for (auto i = count_t{0}; i < n; ++i) {
- visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
- s = relaxed_->d.sizes[i];
- assert(s);
- }
- }
- }
-
- template <typename Visitor, typename... Args>
- void each_right_sub(Visitor v, Args&&... args)
- {
- each_right(v, 1, std::forward<Args>(args)...);
- }
-
- template <typename Visitor, typename... Args>
- void each_right(Visitor v, count_t start, Args&&... args)
- {
- assert(start > 0);
- assert(start <= relaxed_->d.count);
- auto s = relaxed_->d.sizes[start - 1];
- auto p = node_->inner();
- if (shift_ == BL) {
- for (auto i = start; i < relaxed_->d.count; ++i) {
- IMMER_PREFETCH(p + i + 1);
- make_leaf_sub_pos(p[i], relaxed_->d.sizes[i] - s)
- .visit(v, args...);
- s = relaxed_->d.sizes[i];
- assert(s);
- }
- } else {
- auto ss = shift_ - B;
- for (auto i = start; i < relaxed_->d.count; ++i) {
- visit_maybe_relaxed_sub(
- p[i], ss, relaxed_->d.sizes[i] - s, v, args...);
- s = relaxed_->d.sizes[i];
- assert(s);
- }
- }
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards(Visitor v, size_t idx, Args&&... args)
- {
- return towards_oh(v, idx, subindex(idx), args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- assert(offset_hint == index(idx));
- auto left_size = offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0;
- return towards_oh_sbh(v, idx, offset_hint, left_size, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards_oh_sbh(Visitor v,
- size_t idx,
- count_t offset_hint,
- size_t left_size_hint,
- Args&&... args)
- {
- return towards_sub_oh_sbh(v, idx, offset_hint, left_size_hint, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto)
- towards_sub_oh(Visitor v, size_t idx, count_t offset_hint, Args&&... args)
- {
- assert(offset_hint == index(idx));
- auto left_size = offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0;
- return towards_sub_oh_sbh(v, idx, offset_hint, left_size, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) towards_sub_oh_sbh(Visitor v,
- size_t idx,
- count_t offset_hint,
- size_t left_size_hint,
- Args&&... args)
- {
- assert(offset_hint == index(idx));
- assert(left_size_hint ==
- (offset_hint ? relaxed_->d.sizes[offset_hint - 1] : 0));
- auto child = node_->inner()[offset_hint];
- auto is_leaf = shift_ == BL;
- auto next_size = relaxed_->d.sizes[offset_hint] - left_size_hint;
- auto next_idx = idx - left_size_hint;
- return is_leaf
- ? make_leaf_sub_pos(child, next_size)
- .visit(v, next_idx, args...)
- : visit_maybe_relaxed_sub(
- child, shift_ - B, next_size, v, next_idx, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_oh_csh(Visitor v,
- count_t offset_hint,
- size_t child_size_hint,
- Args&&... args)
- {
- assert(offset_hint == count() - 1);
- assert(child_size_hint == size(offset_hint));
- auto child = node_->inner()[offset_hint];
- auto is_leaf = shift_ == BL;
- return is_leaf
- ? make_leaf_sub_pos(child, child_size_hint).visit(v, args...)
- : visit_maybe_relaxed_sub(
- child, shift_ - B, child_size_hint, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) last_sub(Visitor v, Args&&... args)
- {
- auto offset = relaxed_->d.count - 1;
- auto child = node_->inner()[offset];
- auto child_size = size(offset);
- auto is_leaf = shift_ == BL;
- return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
- : visit_maybe_relaxed_sub(
- child, shift_ - B, child_size, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub(Visitor v, Args&&... args)
- {
- auto child = node_->inner()[0];
- auto child_size = relaxed_->d.sizes[0];
- auto is_leaf = shift_ == BL;
- assert(child_size);
- return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
- : visit_maybe_relaxed_sub(
- child, shift_ - B, child_size, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_leaf(Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- auto child = node_->inner()[0];
- auto child_size = relaxed_->d.sizes[0];
- return make_leaf_sub_pos(child, child_size).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) first_sub_inner(Visitor v, Args&&... args)
- {
- assert(shift_ > BL);
- auto child = node_->inner()[0];
- auto child_size = relaxed_->d.sizes[0];
- return visit_maybe_relaxed_sub(
- child, shift_ - B, child_size, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub(count_t offset, Visitor v, Args&&... args)
- {
- auto child = node_->inner()[offset];
- auto child_size = size(offset);
- auto is_leaf = shift_ == BL;
- return is_leaf ? make_leaf_sub_pos(child, child_size).visit(v, args...)
- : visit_maybe_relaxed_sub(
- child, shift_ - B, child_size, v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) nth_sub_leaf(count_t offset, Visitor v, Args&&... args)
- {
- assert(shift_ == BL);
- auto child = node_->inner()[offset];
- auto child_size = size(offset);
- return make_leaf_sub_pos(child, child_size).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename Pos>
-using is_relaxed = std::is_same<relaxed_pos<typename std::decay_t<Pos>::node_t>,
- std::decay_t<Pos>>;
-
-template <typename Pos>
-constexpr auto is_relaxed_v = is_relaxed<Pos>::value;
-
-template <typename NodeT>
-relaxed_pos<NodeT>
-make_relaxed_pos(NodeT* node, shift_t shift, typename NodeT::relaxed_t* relaxed)
-{
- assert(node);
- assert(relaxed);
- assert(shift >= NodeT::bits_leaf);
- return {node, shift, relaxed};
-}
-
-template <typename NodeT, typename Visitor, typename... Args>
-decltype(auto) visit_maybe_relaxed_sub(
- NodeT* node, shift_t shift, size_t size, Visitor v, Args&&... args)
-{
- assert(node);
- auto relaxed = node->relaxed();
- if (relaxed) {
- assert(size == relaxed->d.sizes[relaxed->d.count - 1]);
- return make_relaxed_pos(node, shift, relaxed)
- .visit(v, std::forward<Args>(args)...);
- } else {
- return make_regular_sub_pos(node, shift, size)
- .visit(v, std::forward<Args>(args)...);
- }
-}
-
-template <typename NodeT,
- shift_t Shift,
- bits_t B = NodeT::bits,
- bits_t BL = NodeT::bits_leaf>
-struct relaxed_descent_pos
-{
- static_assert(Shift > 0, "not leaf...");
-
- using node_t = NodeT;
- using relaxed_t = typename NodeT::relaxed_t;
- node_t* node_;
- relaxed_t* relaxed_;
-
- count_t count() const { return relaxed_->d.count; }
- node_t* node() const { return node_; }
- shift_t shift() const { return Shift; }
- size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
-
- count_t index(size_t idx) const
- {
- // make gcc happy
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshift-count-overflow"
-#endif
- auto offset = idx >> Shift;
-#if !defined(_MSC_VER)
-#pragma GCC diagnostic pop
-#endif
- while (relaxed_->d.sizes[offset] <= idx)
- ++offset;
- return offset;
- }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx)
- {
- auto offset = index(idx);
- auto child = node_->inner()[offset];
- auto left_size = offset ? relaxed_->d.sizes[offset - 1] : 0;
- auto next_idx = idx - left_size;
- auto r = child->relaxed();
- return r ? relaxed_descent_pos<NodeT, Shift - B>{child, r}.visit(
- v, next_idx)
- : regular_descent_pos<NodeT, Shift - B>{child}.visit(v,
- next_idx);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT, bits_t B, bits_t BL>
-struct relaxed_descent_pos<NodeT, BL, B, BL>
-{
- using node_t = NodeT;
- using relaxed_t = typename NodeT::relaxed_t;
- node_t* node_;
- relaxed_t* relaxed_;
-
- count_t count() const { return relaxed_->d.count; }
- node_t* node() const { return node_; }
- shift_t shift() const { return BL; }
- size_t size() const { return relaxed_->d.sizes[relaxed_->d.count - 1]; }
-
- count_t index(size_t idx) const
- {
- auto offset = (idx >> BL) & mask<B>;
- while (relaxed_->d.sizes[offset] <= idx)
- ++offset;
- return offset;
- }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx)
- {
- auto offset = index(idx);
- auto child = node_->inner()[offset];
- auto left_size = offset ? relaxed_->d.sizes[offset - 1] : 0;
- auto next_idx = idx - left_size;
- return leaf_descent_pos<NodeT>{child}.visit(v, next_idx);
- }
-
- template <typename Visitor, typename... Args>
- decltype(auto) visit(Visitor v, Args&&... args)
- {
- return Visitor::visit_relaxed(*this, std::forward<Args>(args)...);
- }
-};
-
-template <typename NodeT, typename Visitor, typename... Args>
-decltype(auto)
-visit_maybe_relaxed_descent(NodeT* node, shift_t shift, Visitor v, size_t idx)
-{
- constexpr auto B = NodeT::bits;
- constexpr auto BL = NodeT::bits_leaf;
- assert(node);
- assert(shift >= BL);
- auto r = node->relaxed();
- if (r) {
- switch (shift) {
- case BL + B * 0:
- return relaxed_descent_pos<NodeT, BL + B * 0>{node, r}.visit(v,
- idx);
- case BL + B * 1:
- return relaxed_descent_pos<NodeT, BL + B * 1>{node, r}.visit(v,
- idx);
- case BL + B * 2:
- return relaxed_descent_pos<NodeT, BL + B * 2>{node, r}.visit(v,
- idx);
- case BL + B * 3:
- return relaxed_descent_pos<NodeT, BL + B * 3>{node, r}.visit(v,
- idx);
- case BL + B * 4:
- return relaxed_descent_pos<NodeT, BL + B * 4>{node, r}.visit(v,
- idx);
- case BL + B * 5:
- return relaxed_descent_pos<NodeT, BL + B * 5>{node, r}.visit(v,
- idx);
-#if IMMER_DESCENT_DEEP
- default:
- for (auto level = shift; level != endshift<B, BL>; level -= B) {
- auto r = node->relaxed();
- if (r) {
- auto node_idx = (idx >> level) & mask<B>;
- while (r->d.sizes[node_idx] <= idx)
- ++node_idx;
- if (node_idx)
- idx -= r->d.sizes[node_idx - 1];
- node = node->inner()[node_idx];
- } else {
- do {
- node = node->inner()[(idx >> level) & mask<B>];
- } while ((level -= B) != endshift<B, BL>);
- return make_leaf_descent_pos(node).visit(v, idx);
- }
- }
- return make_leaf_descent_pos(node).visit(v, idx);
-#endif // IMMER_DESCENT_DEEP
- }
- IMMER_UNREACHABLE;
- } else {
- return visit_regular_descent(node, shift, v, idx);
- }
-}
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/rbtree.hpp b/src/third_party/immer/dist/immer/detail/rbts/rbtree.hpp
deleted file mode 100644
index c8fa4251f05..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/rbtree.hpp
+++ /dev/null
@@ -1,534 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/rbts/node.hpp>
-#include <immer/detail/rbts/operations.hpp>
-#include <immer/detail/rbts/position.hpp>
-#include <immer/detail/type_traits.hpp>
-
-#include <cassert>
-#include <memory>
-#include <numeric>
-#include <stdexcept>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T, typename MemoryPolicy, bits_t B, bits_t BL>
-struct rbtree
-{
- using node_t = node<T, MemoryPolicy, B, BL>;
- using edit_t = typename node_t::edit_t;
- using owner_t = typename MemoryPolicy::transience_t::owner;
-
- size_t size;
- shift_t shift;
- node_t* root;
- node_t* tail;
-
- constexpr static size_t max_size()
- {
- auto S = sizeof(size_t) * 8;
- return (size_t{1} << BL) * ipow(size_t{1} << B, (S - BL) / B);
- }
-
- static node_t* empty_root()
- {
- static const auto empty_ = node_t::make_inner_n(0u);
- return empty_->inc();
- }
-
- static node_t* empty_tail()
- {
- static const auto empty_ = node_t::make_leaf_n(0u);
- return empty_->inc();
- }
-
- template <typename U>
- static auto from_initializer_list(std::initializer_list<U> values)
- {
- auto e = owner_t{};
- auto result = rbtree{};
- for (auto&& v : values)
- result.push_back_mut(e, v);
- return result;
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<compatible_sentinel_v<Iter, Sent>, bool> = true>
- static auto from_range(Iter first, Sent last)
- {
- auto e = owner_t{};
- auto result = rbtree{};
- for (; first != last; ++first)
- result.push_back_mut(e, *first);
- return result;
- }
-
- static auto from_fill(size_t n, T v)
- {
- auto e = owner_t{};
- auto result = rbtree{};
- while (n-- > 0)
- result.push_back_mut(e, v);
- return result;
- }
-
- rbtree()
- : size{0}
- , shift{BL}
- , root{empty_root()}
- , tail{empty_tail()}
- {
- assert(check_tree());
- }
-
- rbtree(size_t sz, shift_t sh, node_t* r, node_t* t)
- : size{sz}
- , shift{sh}
- , root{r}
- , tail{t}
- {
- assert(check_tree());
- }
-
- rbtree(const rbtree& other)
- : rbtree{other.size, other.shift, other.root, other.tail}
- {
- inc();
- }
-
- rbtree(rbtree&& other)
- : rbtree{}
- {
- swap(*this, other);
- }
-
- rbtree& operator=(const rbtree& other)
- {
- auto next = other;
- swap(*this, next);
- return *this;
- }
-
- rbtree& operator=(rbtree&& other)
- {
- swap(*this, other);
- return *this;
- }
-
- friend void swap(rbtree& x, rbtree& y)
- {
- using std::swap;
- swap(x.size, y.size);
- swap(x.shift, y.shift);
- swap(x.root, y.root);
- swap(x.tail, y.tail);
- }
-
- ~rbtree() { dec(); }
-
- void inc() const
- {
- root->inc();
- tail->inc();
- }
-
- void dec() const { traverse(dec_visitor()); }
-
- auto tail_size() const { return size ? ((size - 1) & mask<BL>) +1 : 0; }
-
- auto tail_offset() const { return size ? (size - 1) & ~mask<BL> : 0; }
-
- template <typename Visitor, typename... Args>
- void traverse(Visitor v, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
-
- if (tail_off)
- make_regular_sub_pos(root, shift, tail_off).visit(v, args...);
- else
- make_empty_regular_pos(root).visit(v, args...);
-
- make_leaf_sub_pos(tail, tail_size).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- void traverse(Visitor v, size_t first, size_t last, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
-
- if (first < tail_off)
- make_regular_sub_pos(root, shift, tail_off)
- .visit(v, first, last < tail_off ? last : tail_off, args...);
- if (last > tail_off)
- make_leaf_sub_pos(tail, tail_size)
- .visit(v,
- first > tail_off ? first - tail_off : 0,
- last - tail_off,
- args...);
- }
-
- template <typename Visitor, typename... Args>
- bool traverse_p(Visitor v, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
- return (tail_off ? make_regular_sub_pos(root, shift, tail_off)
- .visit(v, args...)
- : make_empty_regular_pos(root).visit(v, args...)) &&
- make_leaf_sub_pos(tail, tail_size).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- bool traverse_p(Visitor v, size_t first, size_t last, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
-
- return (first < tail_off ? make_regular_sub_pos(root, shift, tail_off)
- .visit(v,
- first,
- last < tail_off ? last : tail_off,
- args...)
- : true) &&
- (last > tail_off
- ? make_leaf_sub_pos(tail, tail_size)
- .visit(v,
- first > tail_off ? first - tail_off : 0,
- last - tail_off,
- args...)
- : true);
- }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx) const
- {
- auto tail_off = tail_offset();
- return idx >= tail_off ? make_leaf_descent_pos(tail).visit(v, idx)
- : visit_regular_descent(root, shift, v, idx);
- }
-
- template <typename Fn>
- void for_each_chunk(Fn&& fn) const
- {
- traverse(for_each_chunk_visitor{}, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- void for_each_chunk(size_t first, size_t last, Fn&& fn) const
- {
- traverse(for_each_chunk_i_visitor{}, first, last, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- bool for_each_chunk_p(Fn&& fn) const
- {
- return traverse_p(for_each_chunk_p_visitor{}, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- bool for_each_chunk_p(size_t first, size_t last, Fn&& fn) const
- {
- return traverse_p(
- for_each_chunk_p_i_visitor{}, first, last, std::forward<Fn>(fn));
- }
-
- bool equals(const rbtree& other) const
- {
- if (size != other.size)
- return false;
- if (size == 0)
- return true;
- return (size <= branches<BL> ||
- make_regular_sub_pos(root, shift, tail_offset())
- .visit(equals_visitor{}, other.root)) &&
- make_leaf_sub_pos(tail, tail_size())
- .visit(equals_visitor{}, other.tail);
- }
-
- void ensure_mutable_tail(edit_t e, count_t n)
- {
- if (!tail->can_mutate(e)) {
- auto new_tail = node_t::copy_leaf_e(e, tail, n);
- dec_leaf(tail, n);
- tail = new_tail;
- }
- }
-
- void push_back_mut(edit_t e, T value)
- {
- auto tail_off = tail_offset();
- auto ts = size - tail_off;
- if (ts < branches<BL>) {
- ensure_mutable_tail(e, ts);
- new (&tail->leaf()[ts]) T{std::move(value)};
- } else {
- auto new_tail = node_t::make_leaf_e(e, std::move(value));
- IMMER_TRY {
- if (tail_off == size_t{branches<B>} << shift) {
- auto new_root = node_t::make_inner_e(e);
- IMMER_TRY {
- auto path = node_t::make_path_e(e, shift, tail);
- new_root->inner()[0] = root;
- new_root->inner()[1] = path;
- root = new_root;
- tail = new_tail;
- shift += B;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_e(new_root);
- IMMER_RETHROW;
- }
- } else if (tail_off) {
- auto new_root =
- make_regular_sub_pos(root, shift, tail_off)
- .visit(push_tail_mut_visitor<node_t>{}, e, tail);
- root = new_root;
- tail = new_tail;
- } else {
- auto new_root = node_t::make_path_e(e, shift, tail);
- assert(tail_off == 0);
- dec_empty_regular(root);
- root = new_root;
- tail = new_tail;
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, 1);
- IMMER_RETHROW;
- }
- }
- ++size;
- }
-
- rbtree push_back(T value) const
- {
- auto tail_off = tail_offset();
- auto ts = size - tail_off;
- if (ts < branches<BL>) {
- auto new_tail =
- node_t::copy_leaf_emplace(tail, ts, std::move(value));
- return {size + 1, shift, root->inc(), new_tail};
- } else {
- auto new_tail = node_t::make_leaf_n(1, std::move(value));
- IMMER_TRY {
- if (tail_off == size_t{branches<B>} << shift) {
- auto new_root = node_t::make_inner_n(2);
- IMMER_TRY {
- auto path = node_t::make_path(shift, tail);
- new_root->inner()[0] = root;
- new_root->inner()[1] = path;
- root->inc();
- tail->inc();
- return {size + 1, shift + B, new_root, new_tail};
- }
- IMMER_CATCH (...) {
- node_t::delete_inner(new_root, 2);
- IMMER_RETHROW;
- }
- } else if (tail_off) {
- auto new_root =
- make_regular_sub_pos(root, shift, tail_off)
- .visit(push_tail_visitor<node_t>{}, tail);
- tail->inc();
- return {size + 1, shift, new_root, new_tail};
- } else {
- auto new_root = node_t::make_path(shift, tail);
- tail->inc();
- return {size + 1, shift, new_root, new_tail};
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, 1);
- IMMER_RETHROW;
- }
- }
- }
-
- const T* array_for(size_t index) const
- {
- return descend(array_for_visitor<T>(), index);
- }
-
- T& get_mut(edit_t e, size_t idx)
- {
- auto tail_off = tail_offset();
- if (idx >= tail_off) {
- ensure_mutable_tail(e, size - tail_off);
- return tail->leaf()[idx & mask<BL>];
- } else {
- return make_regular_sub_pos(root, shift, tail_off)
- .visit(get_mut_visitor<node_t>{}, idx, e, &root);
- }
- }
-
- const T& get(size_t index) const
- {
- return descend(get_visitor<T>(), index);
- }
-
- const T& get_check(size_t index) const
- {
- if (index >= size)
- IMMER_THROW(std::out_of_range{"index out of range"});
- return descend(get_visitor<T>(), index);
- }
-
- const T& front() const { return get(0); }
-
- const T& back() const { return tail->leaf()[(size - 1) & mask<BL>]; }
-
- template <typename FnT>
- void update_mut(edit_t e, size_t idx, FnT&& fn)
- {
- auto& elem = get_mut(e, idx);
- elem = std::forward<FnT>(fn)(std::move(elem));
- }
-
- template <typename FnT>
- rbtree update(size_t idx, FnT&& fn) const
- {
- auto tail_off = tail_offset();
- if (idx >= tail_off) {
- auto tail_size = size - tail_off;
- auto new_tail =
- make_leaf_sub_pos(tail, tail_size)
- .visit(update_visitor<node_t>{}, idx - tail_off, fn);
- return {size, shift, root->inc(), new_tail};
- } else {
- auto new_root = make_regular_sub_pos(root, shift, tail_off)
- .visit(update_visitor<node_t>{}, idx, fn);
- return {size, shift, new_root, tail->inc()};
- }
- }
-
- void assoc_mut(edit_t e, size_t idx, T value)
- {
- update_mut(e, idx, [&](auto&&) { return std::move(value); });
- }
-
- rbtree assoc(size_t idx, T value) const
- {
- return update(idx, [&](auto&&) { return std::move(value); });
- }
-
- rbtree take(size_t new_size) const
- {
- auto tail_off = tail_offset();
- if (new_size == 0) {
- return {};
- } else if (new_size >= size) {
- return *this;
- } else if (new_size > tail_off) {
- auto new_tail = node_t::copy_leaf(tail, new_size - tail_off);
- return {new_size, shift, root->inc(), new_tail};
- } else {
- using std::get;
- auto l = new_size - 1;
- auto v = slice_right_visitor<node_t>();
- auto r = make_regular_sub_pos(root, shift, tail_off).visit(v, l);
- auto new_shift = get<0>(r);
- auto new_root = get<1>(r);
- auto new_tail = get<3>(r);
- if (new_root) {
- IMMER_ASSERT_TAGGED(new_root->compute_shift() == get<0>(r));
- assert(new_root->check(new_shift, new_size - get<2>(r)));
- return {new_size, new_shift, new_root, new_tail};
- } else {
- return {new_size, BL, empty_root(), new_tail};
- }
- }
- }
-
- void take_mut(edit_t e, size_t new_size)
- {
- auto tail_off = tail_offset();
- if (new_size == 0) {
- // todo: more efficient?
- *this = {};
- } else if (new_size >= size) {
- return;
- } else if (new_size > tail_off) {
- auto ts = size - tail_off;
- auto newts = new_size - tail_off;
- if (tail->can_mutate(e)) {
- detail::destroy_n(tail->leaf() + newts, ts - newts);
- } else {
- auto new_tail = node_t::copy_leaf_e(e, tail, newts);
- dec_leaf(tail, ts);
- tail = new_tail;
- }
- size = new_size;
- return;
- } else {
- using std::get;
- auto l = new_size - 1;
- auto v = slice_right_mut_visitor<node_t>();
- auto r = make_regular_sub_pos(root, shift, tail_off).visit(v, l, e);
- auto new_shift = get<0>(r);
- auto new_root = get<1>(r);
- auto new_tail = get<3>(r);
- if (new_root) {
- root = new_root;
- shift = new_shift;
- } else {
- root = empty_root();
- shift = BL;
- }
- dec_leaf(tail, size - tail_off);
- size = new_size;
- tail = new_tail;
- return;
- }
- }
-
- bool check_tree() const
- {
-#if IMMER_DEBUG_DEEP_CHECK
- assert(shift >= BL);
- assert(tail_offset() <= size);
- assert(check_root());
- assert(check_tail());
-#endif
- return true;
- }
-
- bool check_tail() const
- {
-#if IMMER_DEBUG_DEEP_CHECK
- if (tail_size() > 0)
- assert(tail->check(endshift<B, BL>, tail_size()));
-#endif
- return true;
- }
-
- bool check_root() const
- {
-#if IMMER_DEBUG_DEEP_CHECK
- if (tail_offset() > 0)
- assert(root->check(shift, tail_offset()));
- else {
- IMMER_ASSERT_TAGGED(root->kind() == node_t::kind_t::inner);
- assert(shift == BL);
- }
-#endif
- return true;
- }
-};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/rbtree_iterator.hpp b/src/third_party/immer/dist/immer/detail/rbts/rbtree_iterator.hpp
deleted file mode 100644
index 90613b10b98..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/rbtree_iterator.hpp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/iterator_facade.hpp>
-#include <immer/detail/rbts/rbtree.hpp>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T, typename MP, bits_t B, bits_t BL>
-struct rbtree_iterator
- : iterator_facade<rbtree_iterator<T, MP, B, BL>,
- std::random_access_iterator_tag,
- T,
- const T&,
- std::ptrdiff_t,
- const T*>
-{
- using tree_t = rbtree<T, MP, B, BL>;
-
- struct end_t
- {};
-
- rbtree_iterator() = default;
-
- rbtree_iterator(const tree_t& v)
- : v_{&v}
- , i_{0}
- , base_{~size_t{}}
- , curr_{nullptr}
- {}
-
- rbtree_iterator(const tree_t& v, end_t)
- : v_{&v}
- , i_{v.size}
- , base_{~size_t{}}
- , curr_{nullptr}
- {}
-
- const tree_t& impl() const { return *v_; }
- size_t index() const { return i_; }
-
-private:
- friend iterator_core_access;
-
- const tree_t* v_;
- size_t i_;
- mutable size_t base_;
- mutable const T* curr_ = nullptr;
-
- void increment()
- {
- assert(i_ < v_->size);
- ++i_;
- }
-
- void decrement()
- {
- assert(i_ > 0);
- --i_;
- }
-
- void advance(std::ptrdiff_t n)
- {
- assert(n <= 0 || i_ + static_cast<size_t>(n) <= v_->size);
- assert(n >= 0 || static_cast<size_t>(-n) <= i_);
- i_ += n;
- }
-
- bool equal(const rbtree_iterator& other) const { return i_ == other.i_; }
-
- std::ptrdiff_t distance_to(const rbtree_iterator& other) const
- {
- return other.i_ > i_ ? static_cast<std::ptrdiff_t>(other.i_ - i_)
- : -static_cast<std::ptrdiff_t>(i_ - other.i_);
- }
-
- const T& dereference() const
- {
- auto base = i_ & ~mask<BL>;
- if (base_ != base) {
- base_ = base;
- curr_ = v_->array_for(i_);
- }
- return curr_[i_ & mask<BL>];
- }
-};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/rrbtree.hpp b/src/third_party/immer/dist/immer/detail/rbts/rrbtree.hpp
deleted file mode 100644
index 67f052f4ff8..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/rrbtree.hpp
+++ /dev/null
@@ -1,1450 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/rbts/node.hpp>
-#include <immer/detail/rbts/operations.hpp>
-#include <immer/detail/rbts/position.hpp>
-
-#include <immer/detail/type_traits.hpp>
-
-#include <cassert>
-#include <limits>
-#include <memory>
-#include <numeric>
-#include <stdexcept>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T, typename MemoryPolicy, bits_t B, bits_t BL>
-struct rrbtree_iterator;
-
-template <typename T, typename MemoryPolicy, bits_t B, bits_t BL>
-struct rrbtree
-{
- using node_t = node<T, MemoryPolicy, B, BL>;
- using edit_t = typename node_t::edit_t;
- using owner_t = typename MemoryPolicy::transience_t::owner;
-
- size_t size;
- shift_t shift;
- node_t* root;
- node_t* tail;
-
- constexpr static size_t max_size()
- {
- auto S = sizeof(size_t) * 8;
- return ((size_t{1} << BL) - std::min(size_t{BL}, size_t{2})) *
- ipow((size_t{1} << B) - 2, (S - BL) / B);
- }
-
- static node_t* empty_root()
- {
- static const auto empty_ = [&] {
- static std::aligned_storage_t<node_t::sizeof_inner_n(0),
- alignof(std::max_align_t)>
- storage;
- return node_t::make_inner_n_into(
- &storage, node_t::sizeof_inner_n(0), 0u);
- }();
- return empty_->inc();
- }
-
- static node_t* empty_tail()
- {
- static const auto empty_ = [&] {
- static std::aligned_storage_t<node_t::sizeof_leaf_n(0),
- alignof(std::max_align_t)>
- storage;
- return node_t::make_leaf_n_into(
- &storage, node_t::sizeof_leaf_n(0), 0u);
- }();
- return empty_->inc();
- }
-
- template <typename U>
- static auto from_initializer_list(std::initializer_list<U> values)
- {
- auto e = owner_t{};
- auto result = rrbtree{};
- for (auto&& v : values)
- result.push_back_mut(e, v);
- return result;
- }
-
- template <typename Iter,
- typename Sent,
- std::enable_if_t<compatible_sentinel_v<Iter, Sent>, bool> = true>
- static auto from_range(Iter first, Sent last)
- {
- auto e = owner_t{};
- auto result = rrbtree{};
- for (; first != last; ++first)
- result.push_back_mut(e, *first);
- return result;
- }
-
- static auto from_fill(size_t n, T v)
- {
- auto e = owner_t{};
- auto result = rrbtree{};
- while (n-- > 0)
- result.push_back_mut(e, v);
- return result;
- }
-
- rrbtree() noexcept
- : size{0}
- , shift{BL}
- , root{empty_root()}
- , tail{empty_tail()}
- {
- assert(check_tree());
- }
-
- rrbtree(size_t sz, shift_t sh, node_t* r, node_t* t) noexcept
- : size{sz}
- , shift{sh}
- , root{r}
- , tail{t}
- {
- assert(check_tree());
- }
-
- rrbtree(const rrbtree& other) noexcept
- : rrbtree{other.size, other.shift, other.root, other.tail}
- {
- inc();
- }
-
- rrbtree(rrbtree&& other) noexcept
- : rrbtree{}
- {
- swap(*this, other);
- }
-
- rrbtree& operator=(const rrbtree& other)
- {
- auto next{other};
- swap(*this, next);
- return *this;
- }
-
- rrbtree& operator=(rrbtree&& other) noexcept
- {
- swap(*this, other);
- return *this;
- }
-
- friend void swap(rrbtree& x, rrbtree& y) noexcept
- {
- using std::swap;
- swap(x.size, y.size);
- swap(x.shift, y.shift);
- swap(x.root, y.root);
- swap(x.tail, y.tail);
- }
-
- ~rrbtree() { dec(); }
-
- void inc() const
- {
- root->inc();
- tail->inc();
- }
-
- void dec() const { traverse(dec_visitor()); }
-
- auto tail_size() const { return size - tail_offset(); }
-
- auto tail_offset() const
- {
- auto r = root->relaxed();
- assert(r == nullptr || r->d.count);
- return r ? r->d.sizes[r->d.count - 1]
- : size ? (size - 1) & ~mask<BL>
- /* otherwise */
- : 0;
- }
-
- template <typename Visitor, typename... Args>
- void traverse(Visitor v, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
-
- if (tail_off)
- visit_maybe_relaxed_sub(root, shift, tail_off, v, args...);
- else
- make_empty_regular_pos(root).visit(v, args...);
-
- if (tail_size)
- make_leaf_sub_pos(tail, tail_size).visit(v, args...);
- else
- make_empty_leaf_pos(tail).visit(v, args...);
- }
-
- template <typename Visitor, typename... Args>
- void traverse(Visitor v, size_t first, size_t last, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
-
- if (first < tail_off)
- visit_maybe_relaxed_sub(root,
- shift,
- tail_off,
- v,
- first,
- last < tail_off ? last : tail_off,
- args...);
- if (last > tail_off)
- make_leaf_sub_pos(tail, tail_size)
- .visit(v,
- first > tail_off ? first - tail_off : 0,
- last - tail_off,
- args...);
- }
-
- template <typename Visitor, typename... Args>
- bool traverse_p(Visitor v, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
- return (tail_off
- ? visit_maybe_relaxed_sub(root, shift, tail_off, v, args...)
- : make_empty_regular_pos(root).visit(v, args...)) &&
- (tail_size ? make_leaf_sub_pos(tail, tail_size).visit(v, args...)
- : make_empty_leaf_pos(tail).visit(v, args...));
- }
-
- template <typename Visitor, typename... Args>
- bool traverse_p(Visitor v, size_t first, size_t last, Args&&... args) const
- {
- auto tail_off = tail_offset();
- auto tail_size = size - tail_off;
- return (first < tail_off
- ? visit_maybe_relaxed_sub(root,
- shift,
- tail_off,
- v,
- first,
- last < tail_off ? last : tail_off,
- args...)
- : true) &&
- (last > tail_off
- ? make_leaf_sub_pos(tail, tail_size)
- .visit(v,
- first > tail_off ? first - tail_off : 0,
- last - tail_off,
- args...)
- : true);
- }
-
- template <typename Visitor>
- decltype(auto) descend(Visitor v, size_t idx) const
- {
- auto tail_off = tail_offset();
- return idx >= tail_off
- ? make_leaf_descent_pos(tail).visit(v, idx - tail_off)
- : visit_maybe_relaxed_descent(root, shift, v, idx);
- }
-
- template <typename Fn>
- void for_each_chunk(Fn&& fn) const
- {
- traverse(for_each_chunk_visitor{}, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- void for_each_chunk(size_t first, size_t last, Fn&& fn) const
- {
- traverse(for_each_chunk_i_visitor{}, first, last, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- bool for_each_chunk_p(Fn&& fn) const
- {
- return traverse_p(for_each_chunk_p_visitor{}, std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- bool for_each_chunk_p(size_t first, size_t last, Fn&& fn) const
- {
- return traverse_p(
- for_each_chunk_p_i_visitor{}, first, last, std::forward<Fn>(fn));
- }
-
- bool equals(const rrbtree& other) const
- {
- using iter_t = rrbtree_iterator<T, MemoryPolicy, B, BL>;
- if (size != other.size)
- return false;
- if (size == 0)
- return true;
- auto tail_off = tail_offset();
- auto tail_off_other = other.tail_offset();
- // compare trees
- if (tail_off > 0 && tail_off_other > 0) {
- // other.shift != shift is a theoretical possibility for
- // relaxed trees that sadly we haven't managed to exercise
- // in tests yet...
- if (other.shift >= shift) {
- if (!visit_maybe_relaxed_sub(other.root,
- other.shift,
- tail_off_other,
- equals_visitor::rrb{},
- iter_t{other},
- root,
- shift,
- tail_off))
- return false;
- } else {
- if (!visit_maybe_relaxed_sub(root,
- shift,
- tail_off,
- equals_visitor::rrb{},
- iter_t{*this},
- other.root,
- other.shift,
- tail_off_other))
- return false;
- }
- }
- return tail_off == tail_off_other
- ? make_leaf_sub_pos(tail, tail_size())
- .visit(equals_visitor{}, other.tail)
- : tail_off > tail_off_other
- ? std::equal(tail->leaf(),
- tail->leaf() + (size - tail_off),
- other.tail->leaf() +
- (tail_off - tail_off_other))
- /* otherwise */
- : std::equal(tail->leaf(),
- tail->leaf() + (size - tail_off),
- iter_t{other} + tail_off);
- }
-
- std::tuple<shift_t, node_t*> push_tail(node_t* root,
- shift_t shift,
- size_t size,
- node_t* tail,
- count_t tail_size) const
- {
- if (auto r = root->relaxed()) {
- auto new_root =
- make_relaxed_pos(root, shift, r)
- .visit(push_tail_visitor<node_t>{}, tail, tail_size);
- if (new_root)
- return std::make_tuple(shift, new_root);
- else {
- auto new_root = node_t::make_inner_r_n(2);
- IMMER_TRY {
- auto new_path = node_t::make_path(shift, tail);
- new_root->inner()[0] = root->inc();
- new_root->inner()[1] = new_path;
- new_root->relaxed()->d.sizes[0] = size;
- new_root->relaxed()->d.sizes[1] = size + tail_size;
- assert(size);
- assert(tail_size);
- new_root->relaxed()->d.count = 2u;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_r(new_root, 2);
- IMMER_RETHROW;
- }
- return std::make_tuple(shift + B, new_root);
- }
- } else if (size == size_t{branches<B>} << shift) {
- auto new_root = node_t::make_inner_n(2);
- IMMER_TRY {
- auto new_path = node_t::make_path(shift, tail);
- new_root->inner()[0] = root->inc();
- new_root->inner()[1] = new_path;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner(new_root, 2);
- IMMER_RETHROW;
- }
- return std::make_tuple(shift + B, new_root);
- } else if (size) {
- auto new_root = make_regular_sub_pos(root, shift, size)
- .visit(push_tail_visitor<node_t>{}, tail);
- return std::make_tuple(shift, new_root);
- } else {
- return std::make_tuple(shift, node_t::make_path(shift, tail));
- }
- }
-
- void
- push_tail_mut(edit_t e, size_t tail_off, node_t* tail, count_t tail_size)
- {
- if (auto r = root->relaxed()) {
- auto new_root =
- make_relaxed_pos(root, shift, r)
- .visit(push_tail_mut_visitor<node_t>{}, e, tail, tail_size);
- if (new_root) {
- root = new_root;
- } else {
- auto new_root = node_t::make_inner_r_e(e);
- IMMER_TRY {
- auto new_path = node_t::make_path_e(e, shift, tail);
- new_root->inner()[0] = root;
- new_root->inner()[1] = new_path;
- new_root->relaxed()->d.sizes[0] = tail_off;
- new_root->relaxed()->d.sizes[1] = tail_off + tail_size;
- assert(tail_off);
- assert(tail_size);
- new_root->relaxed()->d.count = 2u;
- root = new_root;
- shift += B;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_r_e(new_root);
- IMMER_RETHROW;
- }
- }
- } else if (tail_off == size_t{branches<B>} << shift) {
- auto new_root = node_t::make_inner_e(e);
- IMMER_TRY {
- auto new_path = node_t::make_path_e(e, shift, tail);
- new_root->inner()[0] = root;
- new_root->inner()[1] = new_path;
- root = new_root;
- shift += B;
- }
- IMMER_CATCH (...) {
- node_t::delete_inner_e(new_root);
- IMMER_RETHROW;
- }
- } else if (tail_off) {
- auto new_root =
- make_regular_sub_pos(root, shift, tail_off)
- .visit(push_tail_mut_visitor<node_t>{}, e, tail);
- root = new_root;
- } else {
- auto new_root = node_t::make_path_e(e, shift, tail);
- dec_empty_regular(root);
- root = new_root;
- }
- }
-
- void ensure_mutable_tail(edit_t e, count_t n)
- {
- if (!tail->can_mutate(e)) {
- auto new_tail = node_t::copy_leaf_e(e, tail, n);
- dec_leaf(tail, n);
- tail = new_tail;
- }
- }
-
- void push_back_mut(edit_t e, T value)
- {
- auto ts = tail_size();
- if (ts < branches<BL>) {
- ensure_mutable_tail(e, ts);
- new (&tail->leaf()[ts]) T{std::move(value)};
- } else {
- using std::get;
- auto new_tail = node_t::make_leaf_e(e, std::move(value));
- auto tail_off = tail_offset();
- IMMER_TRY {
- push_tail_mut(e, tail_off, tail, ts);
- tail = new_tail;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, 1u);
- IMMER_RETHROW;
- }
- }
- ++size;
- }
-
- rrbtree push_back(T value) const
- {
- auto ts = tail_size();
- if (ts < branches<BL>) {
- auto new_tail =
- node_t::copy_leaf_emplace(tail, ts, std::move(value));
- return {size + 1, shift, root->inc(), new_tail};
- } else {
- using std::get;
- auto new_tail = node_t::make_leaf_n(1u, std::move(value));
- auto tail_off = tail_offset();
- IMMER_TRY {
- auto new_root =
- push_tail(root, shift, tail_off, tail, size - tail_off);
- tail->inc();
- return {size + 1, get<0>(new_root), get<1>(new_root), new_tail};
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, 1u);
- IMMER_RETHROW;
- }
- }
- }
-
- std::tuple<const T*, size_t, size_t> region_for(size_t idx) const
- {
- using std::get;
- auto tail_off = tail_offset();
- if (idx >= tail_off) {
- return std::make_tuple(tail->leaf(), tail_off, size);
- } else {
- auto subs = visit_maybe_relaxed_sub(
- root, shift, tail_off, region_for_visitor<T>(), idx);
- auto first = idx - get<1>(subs);
- auto end = first + get<2>(subs);
- return std::make_tuple(get<0>(subs), first, end);
- }
- }
-
- T& get_mut(edit_t e, size_t idx)
- {
- auto tail_off = tail_offset();
- if (idx >= tail_off) {
- ensure_mutable_tail(e, size - tail_off);
- return tail->leaf()[(idx - tail_off) & mask<BL>];
- } else {
- return visit_maybe_relaxed_sub(root,
- shift,
- tail_off,
- get_mut_visitor<node_t>{},
- idx,
- e,
- &root);
- }
- }
-
- const T& get(size_t index) const
- {
- return descend(get_visitor<T>(), index);
- }
-
- const T& get_check(size_t index) const
- {
- if (index >= size)
- IMMER_THROW(std::out_of_range{"out of range"});
- return descend(get_visitor<T>(), index);
- }
-
- const T& front() const { return get(0); }
-
- const T& back() const { return get(size - 1); }
-
- template <typename FnT>
- void update_mut(edit_t e, size_t idx, FnT&& fn)
- {
- auto& elem = get_mut(e, idx);
- elem = std::forward<FnT>(fn)(std::move(elem));
- }
-
- template <typename FnT>
- rrbtree update(size_t idx, FnT&& fn) const
- {
- auto tail_off = tail_offset();
- if (idx >= tail_off) {
- auto tail_size = size - tail_off;
- auto new_tail =
- make_leaf_sub_pos(tail, tail_size)
- .visit(update_visitor<node_t>{}, idx - tail_off, fn);
- return {size, shift, root->inc(), new_tail};
- } else {
- auto new_root = visit_maybe_relaxed_sub(
- root, shift, tail_off, update_visitor<node_t>{}, idx, fn);
- return {size, shift, new_root, tail->inc()};
- }
- }
-
- void assoc_mut(edit_t e, size_t idx, T value)
- {
- update_mut(e, idx, [&](auto&&) { return std::move(value); });
- }
-
- rrbtree assoc(size_t idx, T value) const
- {
- return update(idx, [&](auto&&) { return std::move(value); });
- }
-
- void take_mut(edit_t e, size_t new_size)
- {
- auto tail_off = tail_offset();
- if (new_size == 0) {
- *this = {};
- } else if (new_size >= size) {
- return;
- } else if (new_size > tail_off) {
- auto ts = size - tail_off;
- auto newts = new_size - tail_off;
- if (tail->can_mutate(e)) {
- detail::destroy_n(tail->leaf() + newts, ts - newts);
- } else {
- auto new_tail = node_t::copy_leaf_e(e, tail, newts);
- dec_leaf(tail, ts);
- tail = new_tail;
- }
- size = new_size;
- return;
- } else {
- using std::get;
- auto l = new_size - 1;
- auto v = slice_right_mut_visitor<node_t>();
- auto r = visit_maybe_relaxed_sub(root, shift, tail_off, v, l, e);
- auto new_shift = get<0>(r);
- auto new_root = get<1>(r);
- auto new_tail = get<3>(r);
- if (new_root) {
- root = new_root;
- shift = new_shift;
- } else {
- root = empty_root();
- shift = BL;
- }
- dec_leaf(tail, size - tail_off);
- size = new_size;
- tail = new_tail;
- return;
- }
- }
-
- rrbtree take(size_t new_size) const
- {
- auto tail_off = tail_offset();
- if (new_size == 0) {
- return {};
- } else if (new_size >= size) {
- return *this;
- } else if (new_size > tail_off) {
- auto new_tail = node_t::copy_leaf(tail, new_size - tail_off);
- return {new_size, shift, root->inc(), new_tail};
- } else {
- using std::get;
- auto l = new_size - 1;
- auto v = slice_right_visitor<node_t>();
- auto r = visit_maybe_relaxed_sub(root, shift, tail_off, v, l);
- auto new_shift = get<0>(r);
- auto new_root = get<1>(r);
- auto new_tail = get<3>(r);
- if (new_root) {
- IMMER_ASSERT_TAGGED(new_root->compute_shift() == get<0>(r));
- assert(new_root->check(new_shift, new_size - get<2>(r)));
- return {new_size, new_shift, new_root, new_tail};
- } else {
- return {new_size, BL, empty_root(), new_tail};
- }
- }
- }
-
- void drop_mut(edit_t e, size_t elems)
- {
- using std::get;
- auto tail_off = tail_offset();
- if (elems == 0) {
- return;
- } else if (elems >= size) {
- *this = {};
- } else if (elems == tail_off) {
- dec_inner(root, shift, tail_off);
- shift = BL;
- root = empty_root();
- size -= elems;
- return;
- } else if (elems > tail_off) {
- auto v = slice_left_mut_visitor<node_t>();
- tail = get<1>(make_leaf_sub_pos(tail, size - tail_off)
- .visit(v, elems - tail_off, e));
- if (tail_off) {
- dec_inner(root, shift, tail_off);
- shift = BL;
- root = empty_root();
- }
- size -= elems;
- return;
- } else {
- auto v = slice_left_mut_visitor<node_t>();
- auto r =
- visit_maybe_relaxed_sub(root, shift, tail_off, v, elems, e);
- shift = get<0>(r);
- root = get<1>(r);
- size -= elems;
- return;
- }
- }
-
- rrbtree drop(size_t elems) const
- {
- if (elems == 0) {
- return *this;
- } else if (elems >= size) {
- return {};
- } else if (elems == tail_offset()) {
- return {size - elems, BL, empty_root(), tail->inc()};
- } else if (elems > tail_offset()) {
- auto tail_off = tail_offset();
- auto new_tail =
- node_t::copy_leaf(tail, elems - tail_off, size - tail_off);
- return {size - elems, BL, empty_root(), new_tail};
- } else {
- using std::get;
- auto v = slice_left_visitor<node_t>();
- auto r =
- visit_maybe_relaxed_sub(root, shift, tail_offset(), v, elems);
- auto new_root = get<1>(r);
- auto new_shift = get<0>(r);
- return {size - elems, new_shift, new_root, tail->inc()};
- }
- }
-
- rrbtree concat(const rrbtree& r) const
- {
- assert(r.size + size <= max_size());
- using std::get;
- if (size == 0)
- return r;
- else if (r.size == 0)
- return *this;
- else if (r.tail_offset() == 0) {
- // just concat the tail, similar to push_back
- auto tail_offst = tail_offset();
- auto tail_size = size - tail_offst;
- if (tail_size == branches<BL>) {
- auto new_root =
- push_tail(root, shift, tail_offst, tail, tail_size);
- tail->inc();
- return {size + r.size,
- get<0>(new_root),
- get<1>(new_root),
- r.tail->inc()};
- } else if (tail_size + r.size <= branches<BL>) {
- auto new_tail =
- node_t::copy_leaf(tail, tail_size, r.tail, r.size);
- return {size + r.size, shift, root->inc(), new_tail};
- } else {
- auto remaining = branches<BL> - tail_size;
- auto add_tail =
- node_t::copy_leaf(tail, tail_size, r.tail, remaining);
- IMMER_TRY {
- auto new_tail =
- node_t::copy_leaf(r.tail, remaining, r.size);
- IMMER_TRY {
- auto new_root = push_tail(
- root, shift, tail_offst, add_tail, branches<BL>);
- return {size + r.size,
- get<0>(new_root),
- get<1>(new_root),
- new_tail};
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, r.size - remaining);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(add_tail, branches<BL>);
- IMMER_RETHROW;
- }
- }
- } else if (tail_offset() == 0) {
- auto tail_offst = tail_offset();
- auto tail_size = size - tail_offst;
- auto concated =
- concat_trees(tail, tail_size, r.root, r.shift, r.tail_offset());
- auto new_shift = concated.shift();
- auto new_root = concated.node();
- IMMER_ASSERT_TAGGED(new_shift == new_root->compute_shift());
- assert(new_root->check(new_shift, size + r.tail_offset()));
- return {size + r.size, new_shift, new_root, r.tail->inc()};
- } else {
- auto tail_offst = tail_offset();
- auto tail_size = size - tail_offst;
- auto concated = concat_trees(root,
- shift,
- tail_offst,
- tail,
- tail_size,
- r.root,
- r.shift,
- r.tail_offset());
- auto new_shift = concated.shift();
- auto new_root = concated.node();
- IMMER_ASSERT_TAGGED(new_shift == new_root->compute_shift());
- assert(new_root->check(new_shift, size + r.tail_offset()));
- return {size + r.size, new_shift, new_root, r.tail->inc()};
- }
- }
-
- constexpr static bool supports_transient_concat =
- !std::is_empty<edit_t>::value;
-
- friend void concat_mut_l(rrbtree& l, edit_t el, const rrbtree& r)
- {
- assert(&l != &r);
- assert(r.size < (std::numeric_limits<size_t>::max() - l.size));
- using std::get;
- if (l.size == 0)
- l = r;
- else if (r.size == 0)
- return;
- else if (r.tail_offset() == 0) {
- // just concat the tail, similar to push_back
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- if (tail_size == branches<BL>) {
- l.push_tail_mut(el, tail_offst, l.tail, tail_size);
- l.tail = r.tail->inc();
- l.size += r.size;
- return;
- } else if (tail_size + r.size <= branches<BL>) {
- l.ensure_mutable_tail(el, tail_size);
- detail::uninitialized_copy(r.tail->leaf(),
- r.tail->leaf() + r.size,
- l.tail->leaf() + tail_size);
- l.size += r.size;
- return;
- } else {
- auto remaining = branches<BL> - tail_size;
- l.ensure_mutable_tail(el, tail_size);
- detail::uninitialized_copy(r.tail->leaf(),
- r.tail->leaf() + remaining,
- l.tail->leaf() + tail_size);
- IMMER_TRY {
- auto new_tail =
- node_t::copy_leaf_e(el, r.tail, remaining, r.size);
- IMMER_TRY {
- l.push_tail_mut(el, tail_offst, l.tail, branches<BL>);
- l.tail = new_tail;
- l.size += r.size;
- return;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, r.size - remaining);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(r.tail->leaf() + tail_size, remaining);
- IMMER_RETHROW;
- }
- }
- } else if (l.tail_offset() == 0) {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated =
- concat_trees_mut(el,
- el,
- l.tail,
- tail_size,
- MemoryPolicy::transience_t::noone,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- l.size += r.size;
- l.shift = concated.shift();
- l.root = concated.node();
- l.tail = r.tail;
- assert(l.check_tree());
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(
- l.tail, tail_size, r.root, r.shift, r.tail_offset());
- l = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- assert(l.check_tree());
- return;
- }
- } else {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- assert(l.check_tree());
- assert(r.check_tree());
- auto concated =
- concat_trees_mut(el,
- el,
- l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- MemoryPolicy::transience_t::noone,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- l.size += r.size;
- l.shift = concated.shift();
- l.root = concated.node();
- l.tail = r.tail;
- assert(l.check_tree());
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- r.root,
- r.shift,
- r.tail_offset());
- l = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- }
- }
- }
-
- friend void concat_mut_r(const rrbtree& l, rrbtree& r, edit_t er)
- {
- assert(&l != &r);
- assert(r.size < (std::numeric_limits<size_t>::max() - l.size));
- using std::get;
- if (r.size == 0)
- r = std::move(l);
- else if (l.size == 0)
- return;
- else if (r.tail_offset() == 0) {
- // just concat the tail, similar to push_back
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- if (tail_size == branches<BL>) {
- // this could be improved by making sure that the
- // newly created nodes as part of the `push_tail()`
- // are tagged with `er`
- auto res =
- l.push_tail(l.root, l.shift, tail_offst, l.tail, tail_size);
- l.tail->inc(); // note: leak if mutably concatenated
- // with itself, but this is forbidden
- // by the interface
- r = {l.size + r.size, get<0>(res), get<1>(res), r.tail->inc()};
- return;
- } else if (tail_size + r.size <= branches<BL>) {
- // doing this in a exception way mutating way is very
- // tricky while potential performance gains are
- // minimal (we need to move every element of the right
- // tail anyways to make space for the left tail)
- //
- // we could however improve this by at least moving the
- // elements of the right tail...
- auto new_tail =
- node_t::copy_leaf(l.tail, tail_size, r.tail, r.size);
- r = {l.size + r.size, l.shift, l.root->inc(), new_tail};
- return;
- } else {
- // like the immutable version
- auto remaining = branches<BL> - tail_size;
- auto add_tail = node_t::copy_leaf_e(
- er, l.tail, tail_size, r.tail, remaining);
- IMMER_TRY {
- auto new_tail =
- node_t::copy_leaf_e(er, r.tail, remaining, r.size);
- IMMER_TRY {
- // this could be improved by making sure that the
- // newly created nodes as part of the `push_tail()`
- // are tagged with `er`
- auto new_root = l.push_tail(l.root,
- l.shift,
- tail_offst,
- add_tail,
- branches<BL>);
- r = {l.size + r.size,
- get<0>(new_root),
- get<1>(new_root),
- new_tail};
- return;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, r.size - remaining);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(add_tail, branches<BL>);
- IMMER_RETHROW;
- }
- }
- } else if (l.tail_offset() == 0) {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated =
- concat_trees_mut(er,
- MemoryPolicy::transience_t::noone,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- r.size += l.size;
- r.shift = concated.shift();
- r.root = concated.node();
- assert(r.check_tree());
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(
- l.tail, tail_size, r.root, r.shift, r.tail_offset());
- r = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- return;
- }
- } else {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated =
- concat_trees_mut(er,
- MemoryPolicy::transience_t::noone,
- l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- r.size += l.size;
- r.shift = concated.shift();
- r.root = concated.node();
- assert(r.check_tree());
- return;
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- r.root,
- r.shift,
- r.tail_offset());
- r = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- return;
- }
- }
- }
-
- friend void concat_mut_lr_l(rrbtree& l, edit_t el, rrbtree& r, edit_t er)
- {
- assert(&l != &r);
- assert(r.size < (std::numeric_limits<size_t>::max() - l.size));
- using std::get;
- if (l.size == 0)
- l = r;
- else if (r.size == 0)
- return;
- else if (r.tail_offset() == 0) {
- // just concat the tail, similar to push_back
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- if (tail_size == branches<BL>) {
- l.push_tail_mut(el, tail_offst, l.tail, tail_size);
- l.tail = r.tail->inc();
- l.size += r.size;
- return;
- } else if (tail_size + r.size <= branches<BL>) {
- l.ensure_mutable_tail(el, tail_size);
- if (r.tail->can_mutate(er))
- detail::uninitialized_move(r.tail->leaf(),
- r.tail->leaf() + r.size,
- l.tail->leaf() + tail_size);
- else
- detail::uninitialized_copy(r.tail->leaf(),
- r.tail->leaf() + r.size,
- l.tail->leaf() + tail_size);
- l.size += r.size;
- return;
- } else {
- auto remaining = branches<BL> - tail_size;
- l.ensure_mutable_tail(el, tail_size);
- if (r.tail->can_mutate(er))
- detail::uninitialized_move(r.tail->leaf(),
- r.tail->leaf() + remaining,
- l.tail->leaf() + tail_size);
- else
- detail::uninitialized_copy(r.tail->leaf(),
- r.tail->leaf() + remaining,
- l.tail->leaf() + tail_size);
- IMMER_TRY {
- auto new_tail =
- node_t::copy_leaf_e(el, r.tail, remaining, r.size);
- IMMER_TRY {
- l.push_tail_mut(el, tail_offst, l.tail, branches<BL>);
- l.tail = new_tail;
- l.size += r.size;
- return;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, r.size - remaining);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- detail::destroy_n(r.tail->leaf() + tail_size, remaining);
- IMMER_RETHROW;
- }
- }
- } else if (l.tail_offset() == 0) {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees_mut(el,
- el,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- l.size += r.size;
- l.shift = concated.shift();
- l.root = concated.node();
- l.tail = r.tail;
- assert(l.check_tree());
- r.hard_reset();
- return;
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(
- l.tail, tail_size, r.root, r.shift, r.tail_offset());
- l = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- return;
- }
- } else {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees_mut(el,
- el,
- l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- l.size += r.size;
- l.shift = concated.shift();
- l.root = concated.node();
- l.tail = r.tail;
- assert(l.check_tree());
- r.hard_reset();
- return;
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- r.root,
- r.shift,
- r.tail_offset());
- l = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- return;
- }
- }
- }
-
- friend void concat_mut_lr_r(rrbtree& l, edit_t el, rrbtree& r, edit_t er)
- {
- assert(&l != &r);
- assert(r.size < (std::numeric_limits<size_t>::max() - l.size));
- using std::get;
- if (r.size == 0)
- r = l;
- else if (l.size == 0)
- return;
- else if (r.tail_offset() == 0) {
- // just concat the tail, similar to push_back
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- if (tail_size == branches<BL>) {
- // this could be improved by making sure that the
- // newly created nodes as part of the `push_tail()`
- // are tagged with `er`
- auto res =
- l.push_tail(l.root, l.shift, tail_offst, l.tail, tail_size);
- r = {l.size + r.size, get<0>(res), get<1>(res), r.tail->inc()};
- return;
- } else if (tail_size + r.size <= branches<BL>) {
- // doing this in a exception way mutating way is very
- // tricky while potential performance gains are
- // minimal (we need to move every element of the right
- // tail anyways to make space for the left tail)
- //
- // we could however improve this by at least moving the
- // elements of the mutable tails...
- auto new_tail =
- node_t::copy_leaf(l.tail, tail_size, r.tail, r.size);
- r = {l.size + r.size, l.shift, l.root->inc(), new_tail};
- return;
- } else {
- // like the immutable version.
- // we could improve this also by moving elements
- // instead of just copying them
- auto remaining = branches<BL> - tail_size;
- auto add_tail = node_t::copy_leaf_e(
- er, l.tail, tail_size, r.tail, remaining);
- IMMER_TRY {
- auto new_tail =
- node_t::copy_leaf_e(er, r.tail, remaining, r.size);
- IMMER_TRY {
- // this could be improved by making sure that the
- // newly created nodes as part of the `push_tail()`
- // are tagged with `er`
- auto new_root = l.push_tail(l.root,
- l.shift,
- tail_offst,
- add_tail,
- branches<BL>);
- r = {l.size + r.size,
- get<0>(new_root),
- get<1>(new_root),
- new_tail};
- return;
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(new_tail, r.size - remaining);
- IMMER_RETHROW;
- }
- }
- IMMER_CATCH (...) {
- node_t::delete_leaf(add_tail, branches<BL>);
- IMMER_RETHROW;
- }
- }
- } else if (l.tail_offset() == 0) {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees_mut(er,
- el,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- assert(concated.node()->check(concated.shift(),
- l.size + r.tail_offset()));
- r.size += l.size;
- r.shift = concated.shift();
- r.root = concated.node();
- assert(r.check_tree());
- l.hard_reset();
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(
- l.tail, tail_size, r.root, r.shift, r.tail_offset());
- r = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- return;
- }
- } else {
- if (supports_transient_concat) {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees_mut(er,
- el,
- l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- er,
- r.root,
- r.shift,
- r.tail_offset());
- IMMER_ASSERT_TAGGED(concated.shift() ==
- concated.node()->compute_shift());
- assert(concated.node()->check(concated.shift(),
- l.size + r.tail_offset()));
- r.size += l.size;
- r.shift = concated.shift();
- r.root = concated.node();
- assert(r.check_tree());
- l.hard_reset();
- } else {
- auto tail_offst = l.tail_offset();
- auto tail_size = l.size - tail_offst;
- auto concated = concat_trees(l.root,
- l.shift,
- tail_offst,
- l.tail,
- tail_size,
- r.root,
- r.shift,
- r.tail_offset());
- r = {l.size + r.size,
- concated.shift(),
- concated.node(),
- r.tail->inc()};
- }
- }
- }
-
- void hard_reset()
- {
- assert(supports_transient_concat);
- size = 0;
- shift = BL;
- root = empty_root();
- tail = empty_tail();
- }
-
- bool check_tree() const
- {
- assert(shift <= sizeof(size_t) * 8 - BL);
- assert(shift >= BL);
- assert(tail_offset() <= size);
- assert(tail_size() <= branches<BL>);
-#if IMMER_DEBUG_DEEP_CHECK
- assert(check_root());
- assert(check_tail());
-#endif
- return true;
- }
-
- bool check_tail() const
- {
-#if IMMER_DEBUG_DEEP_CHECK
- if (tail_size() > 0)
- assert(tail->check(endshift<B, BL>, tail_size()));
-#endif
- return true;
- }
-
- bool check_root() const
- {
-#if IMMER_DEBUG_DEEP_CHECK
- if (tail_offset() > 0)
- assert(root->check(shift, tail_offset()));
- else {
- IMMER_ASSERT_TAGGED(root->kind() == node_t::kind_t::inner);
- assert(shift == BL);
- }
-#endif
- return true;
- }
-
-#if IMMER_DEBUG_PRINT
- void debug_print(std::ostream& out) const
- {
- out << "--" << std::endl
- << "{" << std::endl
- << " size = " << size << std::endl
- << " shift = " << shift << std::endl
- << " root = " << std::endl;
- debug_print_node(out, root, shift, tail_offset());
- out << " tail = " << std::endl;
- debug_print_node(out, tail, endshift<B, BL>, tail_size());
- out << "}" << std::endl;
- }
-
- void debug_print_indent(std::ostream& out, unsigned indent) const
- {
- while (indent-- > 0)
- out << ' ';
- }
-
- void debug_print_node(std::ostream& out,
- node_t* node,
- shift_t shift,
- size_t size,
- unsigned indent = 8) const
- {
- const auto indent_step = 4;
-
- if (shift == endshift<B, BL>) {
- debug_print_indent(out, indent);
- out << "- {" << size << "} "
- << pretty_print_array(node->leaf(), size) << std::endl;
- } else if (auto r = node->relaxed()) {
- auto count = r->d.count;
- debug_print_indent(out, indent);
- out << "# {" << size << "} "
- << pretty_print_array(r->d.sizes, r->d.count) << std::endl;
- auto last_size = size_t{};
- for (auto i = count_t{}; i < count; ++i) {
- debug_print_node(out,
- node->inner()[i],
- shift - B,
- r->d.sizes[i] - last_size,
- indent + indent_step);
- last_size = r->d.sizes[i];
- }
- } else {
- debug_print_indent(out, indent);
- out << "+ {" << size << "}" << std::endl;
- auto count =
- (size >> shift) + (size - ((size >> shift) << shift) > 0);
- if (count) {
- for (auto i = count_t{}; i < count - 1; ++i)
- debug_print_node(out,
- node->inner()[i],
- shift - B,
- 1 << shift,
- indent + indent_step);
- debug_print_node(out,
- node->inner()[count - 1],
- shift - B,
- size - ((count - 1) << shift),
- indent + indent_step);
- }
- }
- }
-#endif // IMMER_DEBUG_PRINT
-};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/rrbtree_iterator.hpp b/src/third_party/immer/dist/immer/detail/rbts/rrbtree_iterator.hpp
deleted file mode 100644
index af967774e7e..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/rrbtree_iterator.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/iterator_facade.hpp>
-#include <immer/detail/rbts/rrbtree.hpp>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename T, typename MP, bits_t B, bits_t BL>
-struct rrbtree_iterator
- : iterator_facade<rrbtree_iterator<T, MP, B, BL>,
- std::random_access_iterator_tag,
- T,
- const T&,
- std::ptrdiff_t,
- const T*>
-{
- using tree_t = rrbtree<T, MP, B, BL>;
- using region_t = std::tuple<const T*, size_t, size_t>;
-
- struct end_t
- {};
-
- const tree_t& impl() const { return *v_; }
- size_t index() const { return i_; }
-
- rrbtree_iterator() = default;
-
- rrbtree_iterator(const tree_t& v)
- : v_{&v}
- , i_{0}
- , curr_{nullptr, ~size_t{}, ~size_t{}}
- {}
-
- rrbtree_iterator(const tree_t& v, end_t)
- : v_{&v}
- , i_{v.size}
- , curr_{nullptr, ~size_t{}, ~size_t{}}
- {}
-
-private:
- friend iterator_core_access;
-
- const tree_t* v_;
- size_t i_;
- mutable region_t curr_;
-
- void increment()
- {
- using std::get;
- assert(i_ < v_->size);
- ++i_;
- }
-
- void decrement()
- {
- using std::get;
- assert(i_ > 0);
- --i_;
- }
-
- void advance(std::ptrdiff_t n)
- {
- using std::get;
- assert(n <= 0 || i_ + static_cast<size_t>(n) <= v_->size);
- assert(n >= 0 || static_cast<size_t>(-n) <= i_);
- i_ += n;
- }
-
- bool equal(const rrbtree_iterator& other) const { return i_ == other.i_; }
-
- std::ptrdiff_t distance_to(const rrbtree_iterator& other) const
- {
- return other.i_ > i_ ? static_cast<std::ptrdiff_t>(other.i_ - i_)
- : -static_cast<std::ptrdiff_t>(i_ - other.i_);
- }
-
- const T& dereference() const
- {
- using std::get;
- if (i_ < get<1>(curr_) || i_ >= get<2>(curr_))
- curr_ = v_->region_for(i_);
- return get<0>(curr_)[i_ - get<1>(curr_)];
- }
-};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/rbts/visitor.hpp b/src/third_party/immer/dist/immer/detail/rbts/visitor.hpp
deleted file mode 100644
index 38cd030c4a9..00000000000
--- a/src/third_party/immer/dist/immer/detail/rbts/visitor.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-
-#include <tuple>
-#include <utility>
-
-namespace immer {
-namespace detail {
-namespace rbts {
-
-template <typename Deriv>
-struct visitor_base
-{
- template <typename... Args>
- static decltype(auto) visit_node(Args&&... args)
- {
- IMMER_UNREACHABLE;
- }
-
- template <typename... Args>
- static decltype(auto) visit_relaxed(Args&&... args)
- {
- return Deriv::visit_inner(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- static decltype(auto) visit_regular(Args&&... args)
- {
- return Deriv::visit_inner(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- static decltype(auto) visit_inner(Args&&... args)
- {
- return Deriv::visit_node(std::forward<Args>(args)...);
- }
-
- template <typename... Args>
- static decltype(auto) visit_leaf(Args&&... args)
- {
- return Deriv::visit_node(std::forward<Args>(args)...);
- }
-};
-
-} // namespace rbts
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/ref_count_base.hpp b/src/third_party/immer/dist/immer/detail/ref_count_base.hpp
deleted file mode 100644
index 28f2e46a99f..00000000000
--- a/src/third_party/immer/dist/immer/detail/ref_count_base.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <atomic>
-
-namespace immer {
-namespace detail {
-
-template <typename Deriv>
-struct ref_count_base
-{
- mutable std::atomic<int> ref_count{0};
-
- friend void intrusive_ptr_add_ref(const Deriv* x)
- {
- x->ref_count.fetch_add(1, std::memory_order_relaxed);
- }
-
- friend void intrusive_ptr_release(const Deriv* x)
- {
- if (x->ref_count.fetch_sub(1, std::memory_order_release) == 1) {
- std::atomic_thread_fence(std::memory_order_acquire);
- delete x;
- }
- }
-};
-
-} /* namespace detail */
-} /* namespace immer */
diff --git a/src/third_party/immer/dist/immer/detail/type_traits.hpp b/src/third_party/immer/dist/immer/detail/type_traits.hpp
deleted file mode 100644
index 091fe04dc28..00000000000
--- a/src/third_party/immer/dist/immer/detail/type_traits.hpp
+++ /dev/null
@@ -1,205 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <algorithm>
-#include <iterator>
-#include <memory>
-#include <type_traits>
-#include <utility>
-
-namespace immer {
-namespace detail {
-
-template <typename... Ts>
-struct make_void
-{
- using type = void;
-};
-
-template <typename... Ts>
-using void_t = typename make_void<Ts...>::type;
-
-template <typename T, typename = void>
-struct is_dereferenceable : std::false_type
-{};
-
-template <typename T>
-struct is_dereferenceable<T, void_t<decltype(*(std::declval<T&>()))>>
- : std::true_type
-{};
-
-template <typename T>
-constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
-
-template <typename T, typename U = T, typename = void>
-struct is_equality_comparable : std::false_type
-{};
-
-template <typename T, typename U>
-struct is_equality_comparable<
- T,
- U,
- std::enable_if_t<std::is_same<bool,
- decltype(std::declval<T&>() ==
- std::declval<U&>())>::value>>
- : std::true_type
-{};
-
-template <typename T, typename U = T>
-constexpr bool is_equality_comparable_v = is_equality_comparable<T, U>::value;
-
-template <typename T, typename U = T, typename = void>
-struct is_inequality_comparable : std::false_type
-{};
-
-template <typename T, typename U>
-struct is_inequality_comparable<
- T,
- U,
- std::enable_if_t<std::is_same<bool,
- decltype(std::declval<T&>() !=
- std::declval<U&>())>::value>>
- : std::true_type
-{};
-
-template <typename T, typename U = T>
-constexpr bool is_inequality_comparable_v =
- is_inequality_comparable<T, U>::value;
-
-template <typename T, typename = void>
-struct is_preincrementable : std::false_type
-{};
-
-template <typename T>
-struct is_preincrementable<
- T,
- std::enable_if_t<std::is_same<T&, decltype(++(std::declval<T&>()))>::value>>
- : std::true_type
-{};
-
-template <typename T>
-constexpr bool is_preincrementable_v = is_preincrementable<T>::value;
-
-template <typename T, typename U = T, typename = void>
-struct is_subtractable : std::false_type
-{};
-
-template <typename T, typename U>
-struct is_subtractable<
- T,
- U,
- void_t<decltype(std::declval<T&>() - std::declval<U&>())>> : std::true_type
-{};
-
-template <typename T, typename U = T>
-constexpr bool is_subtractable_v = is_subtractable<T, U>::value;
-
-namespace swappable {
-
-using std::swap;
-
-template <typename T, typename U, typename = void>
-struct with : std::false_type
-{};
-
-// Does not account for non-referenceable types
-template <typename T, typename U>
-struct with<T,
- U,
- void_t<decltype(swap(std::declval<T&>(), std::declval<U&>())),
- decltype(swap(std::declval<U&>(), std::declval<T&>()))>>
- : std::true_type
-{};
-
-} // namespace swappable
-
-template <typename T, typename U>
-using is_swappable_with = swappable::with<T, U>;
-
-template <typename T>
-using is_swappable = is_swappable_with<T, T>;
-
-template <typename T>
-constexpr bool is_swappable_v = is_swappable_with<T&, T&>::value;
-
-template <typename T, typename = void>
-struct is_iterator : std::false_type
-{};
-
-// See http://en.cppreference.com/w/cpp/concept/Iterator
-template <typename T>
-struct is_iterator<
- T,
- void_t<
- std::enable_if_t<is_preincrementable_v<T> &&
- is_dereferenceable_v<T>
- // accounts for non-referenceable types
- && std::is_copy_constructible<T>::value &&
- std::is_copy_assignable<T>::value &&
- std::is_destructible<T>::value && is_swappable_v<T>>,
- typename std::iterator_traits<T>::value_type,
- typename std::iterator_traits<T>::difference_type,
- typename std::iterator_traits<T>::reference,
- typename std::iterator_traits<T>::pointer,
- typename std::iterator_traits<T>::iterator_category>> : std::true_type
-{};
-
-template <typename T>
-constexpr bool is_iterator_v = is_iterator<T>::value;
-
-template <typename T, typename U, typename = void>
-struct compatible_sentinel : std::false_type
-{};
-
-template <typename T, typename U>
-struct compatible_sentinel<
- T,
- U,
- std::enable_if_t<is_iterator_v<T> && is_equality_comparable_v<T, U> &&
- is_inequality_comparable_v<T, U>>> : std::true_type
-{};
-
-template <typename T, typename U>
-constexpr bool compatible_sentinel_v = compatible_sentinel<T, U>::value;
-
-template <typename T, typename = void>
-struct is_forward_iterator : std::false_type
-{};
-
-template <typename T>
-struct is_forward_iterator<
- T,
- std::enable_if_t<is_iterator_v<T> &&
- std::is_base_of<std::forward_iterator_tag,
- typename std::iterator_traits<
- T>::iterator_category>::value>>
- : std::true_type
-{};
-
-template <typename T>
-constexpr bool is_forward_iterator_v = is_forward_iterator<T>::value;
-
-template <typename T, typename U, typename = void>
-struct std_distance_supports : std::false_type
-{};
-
-template <typename T, typename U>
-struct std_distance_supports<
- T,
- U,
- void_t<decltype(std::distance(std::declval<T>(), std::declval<U>()))>>
- : std::true_type
-{};
-
-template <typename T, typename U>
-constexpr bool std_distance_supports_v = std_distance_supports<T, U>::value;
-
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/detail/util.hpp b/src/third_party/immer/dist/immer/detail/util.hpp
deleted file mode 100644
index d6ae246b43c..00000000000
--- a/src/third_party/immer/dist/immer/detail/util.hpp
+++ /dev/null
@@ -1,314 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-
-#include <cstddef>
-#include <memory>
-#include <new>
-#include <type_traits>
-
-#include <immer/detail/type_traits.hpp>
-
-#if defined(_MSC_VER)
-#include <intrin.h> // for __lzcnt*
-#endif
-
-namespace immer {
-namespace detail {
-
-template <typename T>
-const T* as_const(T* x)
-{
- return x;
-}
-
-template <typename T>
-const T& as_const(T& x)
-{
- return x;
-}
-
-template <typename T>
-using aligned_storage_for =
- typename std::aligned_storage<sizeof(T), alignof(T)>::type;
-
-template <typename T>
-T& auto_const_cast(const T& x)
-{
- return const_cast<T&>(x);
-}
-template <typename T>
-T&& auto_const_cast(const T&& x)
-{
- return const_cast<T&&>(std::move(x));
-}
-
-template <class T>
-inline auto destroy_at(T* p) noexcept
- -> std::enable_if_t<std::is_trivially_destructible<T>::value>
-{
- p->~T();
-}
-
-template <class T>
-inline auto destroy_at(T* p) noexcept
- -> std::enable_if_t<!std::is_trivially_destructible<T>::value>
-{
- p->~T();
-}
-
-template <typename Iter1>
-constexpr bool can_trivially_detroy = std::is_trivially_destructible<
- typename std::iterator_traits<Iter1>::value_type>::value;
-
-template <class Iter>
-auto destroy(Iter, Iter last) noexcept
- -> std::enable_if_t<can_trivially_detroy<Iter>, Iter>
-{
- return last;
-}
-template <class Iter>
-auto destroy(Iter first, Iter last) noexcept
- -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter>
-{
- for (; first != last; ++first)
- detail::destroy_at(std::addressof(*first));
- return first;
-}
-
-template <class Iter, class Size>
-auto destroy_n(Iter first, Size n) noexcept
- -> std::enable_if_t<can_trivially_detroy<Iter>, Iter>
-{
- return first + n;
-}
-template <class Iter, class Size>
-auto destroy_n(Iter first, Size n) noexcept
- -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter>
-{
- for (; n > 0; (void) ++first, --n)
- detail::destroy_at(std::addressof(*first));
- return first;
-}
-
-template <typename Iter1, typename Iter2>
-constexpr bool can_trivially_copy =
- std::is_same<typename std::iterator_traits<Iter1>::value_type,
- typename std::iterator_traits<Iter2>::value_type>::value&&
- std::is_trivially_copyable<
- typename std::iterator_traits<Iter1>::value_type>::value;
-
-template <typename Iter1, typename Iter2>
-auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out) noexcept
- -> std::enable_if_t<can_trivially_copy<Iter1, Iter2>, Iter2>
-{
- return std::copy(first, last, out);
-}
-template <typename Iter1, typename Iter2>
-auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out)
- -> std::enable_if_t<!can_trivially_copy<Iter1, Iter2>, Iter2>
-
-{
- using value_t = typename std::iterator_traits<Iter2>::value_type;
- auto current = out;
- IMMER_TRY {
- for (; first != last; ++first, (void) ++current) {
- ::new (const_cast<void*>(static_cast<const volatile void*>(
- std::addressof(*current)))) value_t(std::move(*first));
- }
- return current;
- }
- IMMER_CATCH (...) {
- detail::destroy(out, current);
- IMMER_RETHROW;
- }
-}
-
-template <typename SourceIter, typename Sent, typename SinkIter>
-auto uninitialized_copy(SourceIter first, Sent last, SinkIter out) noexcept
- -> std::enable_if_t<can_trivially_copy<SourceIter, SinkIter>, SinkIter>
-{
- return std::copy(first, last, out);
-}
-template <typename SourceIter, typename Sent, typename SinkIter>
-auto uninitialized_copy(SourceIter first, Sent last, SinkIter out)
- -> std::enable_if_t<!can_trivially_copy<SourceIter, SinkIter>, SinkIter>
-{
- using value_t = typename std::iterator_traits<SinkIter>::value_type;
- auto current = out;
- IMMER_TRY {
- for (; first != last; ++first, (void) ++current) {
- ::new (const_cast<void*>(static_cast<const volatile void*>(
- std::addressof(*current)))) value_t(*first);
- }
- return current;
- }
- IMMER_CATCH (...) {
- detail::destroy(out, current);
- IMMER_RETHROW;
- }
-}
-
-template <typename Heap, typename T, typename... Args>
-T* make(Args&&... args)
-{
- auto ptr = Heap::allocate(sizeof(T));
- IMMER_TRY {
- return new (ptr) T{std::forward<Args>(args)...};
- }
- IMMER_CATCH (...) {
- Heap::deallocate(sizeof(T), ptr);
- IMMER_RETHROW;
- }
-}
-
-struct not_supported_t
-{};
-struct empty_t
-{};
-
-template <typename T>
-struct exact_t
-{
- T value;
- exact_t(T v)
- : value{v} {};
-};
-
-template <typename T>
-inline constexpr auto clz_(T) -> not_supported_t
-{
- IMMER_UNREACHABLE;
- return {};
-}
-#if defined(_MSC_VER)
-// inline auto clz_(unsigned short x) { return __lzcnt16(x); }
-// inline auto clz_(unsigned int x) { return __lzcnt(x); }
-// inline auto clz_(unsigned __int64 x) { return __lzcnt64(x); }
-#else
-inline constexpr auto clz_(unsigned int x) { return __builtin_clz(x); }
-inline constexpr auto clz_(unsigned long x) { return __builtin_clzl(x); }
-inline constexpr auto clz_(unsigned long long x) { return __builtin_clzll(x); }
-#endif
-
-template <typename T>
-inline constexpr T log2_aux(T x, T r = 0)
-{
- return x <= 1 ? r : log2_aux(x >> 1, r + 1);
-}
-
-template <typename T>
-inline constexpr auto log2(T x) -> std::
- enable_if_t<!std::is_same<decltype(clz_(x)), not_supported_t>::value, T>
-{
- return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - clz_(x);
-}
-
-template <typename T>
-inline constexpr auto log2(T x)
- -> std::enable_if_t<std::is_same<decltype(clz_(x)), not_supported_t>::value,
- T>
-{
- return log2_aux(x);
-}
-
-template <typename T>
-constexpr T ipow(T num, unsigned int pow)
-{
- return pow == 0 ? 1 : num * ipow(num, pow - 1);
-}
-
-template <bool b, typename F>
-auto static_if(F&& f) -> std::enable_if_t<b>
-{
- std::forward<F>(f)(empty_t{});
-}
-template <bool b, typename F>
-auto static_if(F&& f) -> std::enable_if_t<!b>
-{}
-
-template <bool b, typename R = void, typename F1, typename F2>
-auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<b, R>
-{
- return std::forward<F1>(f1)(empty_t{});
-}
-template <bool b, typename R = void, typename F1, typename F2>
-auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<!b, R>
-{
- return std::forward<F2>(f2)(empty_t{});
-}
-
-template <typename T, T value>
-struct constantly
-{
- template <typename... Args>
- T operator()(Args&&...) const
- {
- return value;
- }
-};
-
-/*!
- * An alias to `std::distance`
- */
-template <typename Iterator,
- typename Sentinel,
- std::enable_if_t<detail::std_distance_supports_v<Iterator, Sentinel>,
- bool> = true>
-typename std::iterator_traits<Iterator>::difference_type
-distance(Iterator first, Sentinel last)
-{
- return std::distance(first, last);
-}
-
-/*!
- * Equivalent of the `std::distance` applied to the sentinel-delimited
- * forward range @f$ [first, last) @f$
- */
-template <typename Iterator,
- typename Sentinel,
- std::enable_if_t<
- (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail::
- is_forward_iterator_v<Iterator> &&
- detail::compatible_sentinel_v<Iterator, Sentinel> &&
- (!detail::is_subtractable_v<Sentinel, Iterator>),
- bool> = true>
-typename std::iterator_traits<Iterator>::difference_type
-distance(Iterator first, Sentinel last)
-{
- std::size_t result = 0;
- while (first != last) {
- ++first;
- ++result;
- }
- return result;
-}
-
-/*!
- * Equivalent of the `std::distance` applied to the sentinel-delimited
- * random access range @f$ [first, last) @f$
- */
-template <typename Iterator,
- typename Sentinel,
- std::enable_if_t<
- (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail::
- is_forward_iterator_v<Iterator> &&
- detail::compatible_sentinel_v<Iterator, Sentinel> &&
- detail::is_subtractable_v<Sentinel, Iterator>,
- bool> = true>
-typename std::iterator_traits<Iterator>::difference_type
-distance(Iterator first, Sentinel last)
-{
- return last - first;
-}
-
-} // namespace detail
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/experimental/detail/dvektor_impl.hpp b/src/third_party/immer/dist/immer/experimental/detail/dvektor_impl.hpp
deleted file mode 100644
index 4f697337a70..00000000000
--- a/src/third_party/immer/dist/immer/experimental/detail/dvektor_impl.hpp
+++ /dev/null
@@ -1,499 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/heap_policy.hpp>
-#include <immer/refcount/enable_intrusive_ptr.hpp>
-#include <immer/refcount/refcount_policy.hpp>
-
-#include <boost/intrusive_ptr.hpp>
-#include <boost/iterator/iterator_facade.hpp>
-#include <boost/smart_ptr/intrusive_ref_counter.hpp>
-
-#include <cassert>
-#include <cstddef>
-#include <limits>
-
-namespace immer {
-namespace detail {
-namespace dvektor {
-
-constexpr auto fast_log2(std::size_t x)
-{
- return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - __builtin_clzl(x);
-}
-
-template <int B, typename T = std::size_t>
-constexpr T branches = T{1} << B;
-
-template <int B, typename T = std::size_t>
-constexpr T mask = branches<B, T> - 1;
-
-template <int B, typename T = std::size_t>
-constexpr auto
- max_depth = fast_log2(std::numeric_limits<std::size_t>::max()) / B;
-
-template <typename T, int B, typename MP>
-struct node;
-
-template <typename T, int B, typename MP>
-using node_ptr = boost::intrusive_ptr<node<T, B, MP>>;
-
-template <typename T, int B>
-using leaf_node = std::array<T, 1 << B>;
-
-template <typename T, int B, typename MP>
-using inner_node = std::array<node_ptr<T, B, MP>, 1 << B>;
-
-template <typename T, int B, typename MP>
-struct node
- : enable_intrusive_ptr<node<T, B, MP>, typename MP::refcount>
- , enable_optimized_heap_policy<node<T, B, MP>, typename MP::heap>
-{
- using leaf_node_t = leaf_node<T, B>;
- using inner_node_t = inner_node<T, B, MP>;
-
- enum
- {
- leaf_kind,
- inner_kind
- } kind;
-
- union data_t
- {
- leaf_node_t leaf;
- inner_node_t inner;
- data_t(leaf_node_t n)
- : leaf(std::move(n))
- {}
- data_t(inner_node_t n)
- : inner(std::move(n))
- {}
- ~data_t() {}
- } data;
-
- ~node()
- {
- switch (kind) {
- case leaf_kind:
- data.leaf.~leaf_node_t();
- break;
- case inner_kind:
- data.inner.~inner_node_t();
- break;
- }
- }
-
- node(leaf_node<T, B> n)
- : kind{leaf_kind}
- , data{std::move(n)}
- {}
-
- node(inner_node<T, B, MP> n)
- : kind{inner_kind}
- , data{std::move(n)}
- {}
-
- inner_node_t& inner() &
- {
- assert(kind == inner_kind);
- return data.inner;
- }
- const inner_node_t& inner() const&
- {
- assert(kind == inner_kind);
- return data.inner;
- }
- inner_node_t&& inner() &&
- {
- assert(kind == inner_kind);
- return std::move(data.inner);
- }
-
- leaf_node_t& leaf() &
- {
- assert(kind == leaf_kind);
- return data.leaf;
- }
- const leaf_node_t& leaf() const&
- {
- assert(kind == leaf_kind);
- return data.leaf;
- }
- leaf_node_t&& leaf() &&
- {
- assert(kind == leaf_kind);
- return std::move(data.leaf);
- }
-};
-
-template <typename T, int B, typename MP, typename... Ts>
-auto make_node(Ts&&... xs) -> boost::intrusive_ptr<node<T, B, MP>>
-{
- return new node<T, B, MP>(std::forward<Ts>(xs)...);
-}
-
-template <typename T, int B, typename MP>
-struct ref
-{
- using inner_t = inner_node<T, B, MP>;
- using leaf_t = leaf_node<T, B>;
- using node_t = node<T, B, MP>;
- using node_ptr_t = node_ptr<T, B, MP>;
-
- unsigned depth;
- std::array<node_ptr_t, max_depth<B>> display;
-
- template <typename... Ts>
- static auto make_node(Ts&&... xs)
- {
- return dvektor::make_node<T, B, MP>(std::forward<Ts>(xs)...);
- }
-
- const T& get_elem(std::size_t index, std::size_t xr) const
- {
- auto display_idx = fast_log2(xr) / B;
- auto node = display[display_idx].get();
- auto shift = display_idx * B;
- while (display_idx--) {
- node = node->inner()[(index >> shift) & mask<B>].get();
- shift -= B;
- }
- return node->leaf()[index & mask<B>];
- }
-
- node_ptr_t null_slot_and_copy_inner(node_ptr_t& node, std::size_t idx)
- {
- auto& n = node->inner();
- auto x = node_ptr_t{};
- x.swap(n[idx]);
- return copy_of_inner(x);
- }
-
- node_ptr_t null_slot_and_copy_leaf(node_ptr_t& node, std::size_t idx)
- {
- auto& n = node->inner();
- auto x = node_ptr_t{};
- x.swap(n[idx]);
- return copy_of_leaf(x);
- }
-
- node_ptr_t copy_of_inner(const node_ptr_t& n)
- {
- return make_node(n->inner());
- }
-
- node_ptr_t copy_of_leaf(const node_ptr_t& n)
- {
- return make_node(n->leaf());
- }
-
- void stabilize(std::size_t index)
- {
- auto shift = B;
- for (auto i = 1u; i < depth; ++i) {
- display[i] = copy_of_inner(display[i]);
- display[i]->inner()[(index >> shift) & mask<B>] = display[i - 1];
- shift += B;
- }
- }
-
- void goto_pos_writable_from_clean(std::size_t old_index,
- std::size_t index,
- std::size_t xr)
- {
- assert(depth);
- auto d = depth - 1;
- if (d == 0) {
- display[0] = copy_of_leaf(display[0]);
- } else {
- IMMER_UNREACHABLE;
- display[d] = copy_of_inner(display[d]);
- auto shift = B * d;
- while (--d) {
- display[d] = null_slot_and_copy_inner(
- display[d + 1], (index >> shift) & mask<B>);
- shift -= B;
- }
- display[0] =
- null_slot_and_copy_leaf(display[1], (index >> B) & mask<B>);
- }
- }
-
- void goto_pos_writable_from_dirty(std::size_t old_index,
- std::size_t new_index,
- std::size_t xr)
- {
- assert(depth);
- if (xr < (1 << B)) {
- display[0] = copy_of_leaf(display[0]);
- } else {
- auto display_idx = fast_log2(xr) / B;
- auto shift = B;
- for (auto i = 1u; i <= display_idx; ++i) {
- display[i] = copy_of_inner(display[i]);
- display[i]->inner()[(old_index >> shift) & mask<B>] =
- display[i - 1];
- shift += B;
- }
- for (auto i = display_idx - 1; i > 0; --i) {
- shift -= B;
- display[i] = null_slot_and_copy_inner(
- display[i + 1], (new_index >> shift) & mask<B>);
- }
- display[0] =
- null_slot_and_copy_leaf(display[1], (new_index >> B) & mask<B>);
- }
- }
-
- void goto_fresh_pos_writable_from_clean(std::size_t old_index,
- std::size_t new_index,
- std::size_t xr)
- {
- auto display_idx = fast_log2(xr) / B;
- if (display_idx > 0) {
- auto shift = display_idx * B;
- if (display_idx == depth) {
- display[display_idx] = make_node(inner_t{});
- display[display_idx]->inner()[(old_index >> shift) & mask<B>] =
- display[display_idx - 1];
- ++depth;
- }
- while (--display_idx) {
- auto node = display[display_idx + 1]
- ->inner()[(new_index >> shift) & mask<B>];
- display[display_idx] =
- node ? std::move(node) : make_node(inner_t{});
- }
- display[0] = make_node(leaf_t{});
- }
- }
-
- void goto_fresh_pos_writable_from_dirty(std::size_t old_index,
- std::size_t new_index,
- std::size_t xr)
- {
- stabilize(old_index);
- goto_fresh_pos_writable_from_clean(old_index, new_index, xr);
- }
-
- void goto_next_block_start(std::size_t index, std::size_t xr)
- {
- auto display_idx = fast_log2(xr) / B;
- auto shift = display_idx * B;
- if (display_idx > 0) {
- display[display_idx - 1] =
- display[display_idx]->inner()[(index >> shift) & mask<B>];
- while (--display_idx)
- display[display_idx - 1] = display[display_idx]->inner()[0];
- }
- }
-
- void goto_pos(std::size_t index, std::size_t xr)
- {
- auto display_idx = fast_log2(xr) / B;
- auto shift = display_idx * B;
- if (display_idx) {
- do {
- display[display_idx - 1] =
- display[display_idx]->inner()[(index >> shift) & mask<B>];
- shift -= B;
- } while (--display_idx);
- }
- }
-};
-
-template <typename T, int B, typename MP>
-struct impl
-{
- using inner_t = inner_node<T, B, MP>;
- using leaf_t = leaf_node<T, B>;
- using node_t = node<T, B, MP>;
- using node_ptr_t = node_ptr<T, B, MP>;
- using ref_t = ref<T, B, MP>;
-
- std::size_t size;
- std::size_t focus;
- bool dirty;
- ref_t p;
-
- template <typename... Ts>
- static auto make_node(Ts&&... xs)
- {
- return dvektor::make_node<T, B, MP>(std::forward<Ts>(xs)...);
- }
-
- void goto_pos_writable(std::size_t old_index,
- std::size_t new_index,
- std::size_t xr)
- {
- if (dirty) {
- p.goto_pos_writable_from_dirty(old_index, new_index, xr);
- } else {
- p.goto_pos_writable_from_clean(old_index, new_index, xr);
- dirty = true;
- }
- }
-
- void goto_fresh_pos_writable(std::size_t old_index,
- std::size_t new_index,
- std::size_t xr)
- {
- if (dirty) {
- p.goto_fresh_pos_writable_from_dirty(old_index, new_index, xr);
- } else {
- p.goto_fresh_pos_writable_from_clean(old_index, new_index, xr);
- dirty = true;
- }
- }
-
- impl push_back(T value) const
- {
- if (size) {
- auto block_index = size & ~mask<B>;
- auto lo = size & mask<B>;
- if (size != block_index) {
- auto s = impl{size + 1, block_index, dirty, p};
- s.goto_pos_writable(focus, block_index, focus ^ block_index);
- s.p.display[0]->leaf()[lo] = std::move(value);
- return s;
- } else {
- auto s = impl{size + 1, block_index, dirty, p};
- s.goto_fresh_pos_writable(
- focus, block_index, focus ^ block_index);
- s.p.display[0]->leaf()[lo] = std::move(value);
- return s;
- }
- } else {
- return impl{
- 1, 0, false, {1, {{make_node(leaf_t{{std::move(value)}})}}}};
- }
- }
-
- const T& get(std::size_t index) const
- {
- return p.get_elem(index, index ^ focus);
- }
-
- template <typename FnT>
- impl update(std::size_t idx, FnT&& fn) const
- {
- auto s = impl{size, idx, dirty, p};
- s.goto_pos_writable(focus, idx, focus ^ idx);
- auto& v = s.p.display[0]->leaf()[idx & mask<B>];
- v = fn(std::move(v));
- return s;
- }
-
- impl assoc(std::size_t idx, T value) const
- {
- return update(idx, [&](auto&&) { return std::move(value); });
- }
-};
-
-template <typename T, int B, typename MP>
-const impl<T, B, MP> empty = {0, 0, false, ref<T, B, MP>{1, {}}};
-
-template <typename T, int B, typename MP>
-struct iterator
- : boost::iterator_facade<iterator<T, B, MP>,
- T,
- boost::random_access_traversal_tag,
- const T&>
-{
- struct end_t
- {};
-
- iterator() = default;
-
- iterator(const impl<T, B, MP>& v)
- : p_{v.p}
- , i_{0}
- , base_{0}
- {
- if (v.dirty)
- p_.stabilize(v.focus);
- p_.goto_pos(0, 0 ^ v.focus);
- curr_ = p_.display[0]->leaf().begin();
- }
-
- iterator(const impl<T, B, MP>& v, end_t)
- : p_{v.p}
- , i_{v.size}
- , base_{(v.size - 1) & ~mask<B>}
- {
- if (v.dirty)
- p_.stabilize(v.focus);
- p_.goto_pos(base_, base_ ^ v.focus);
- curr_ = p_.display[0]->leaf().begin() + (i_ - base_);
- }
-
-private:
- friend class boost::iterator_core_access;
- using leaf_iterator = typename leaf_node<T, B>::const_iterator;
-
- ref<T, B, MP> p_;
- std::size_t i_;
- std::size_t base_;
- leaf_iterator curr_;
-
- void increment()
- {
- ++i_;
- if (i_ - base_ < branches<B>) {
- ++curr_;
- } else {
- auto new_base = base_ + branches<B>;
- p_.goto_next_block_start(new_base, base_ ^ new_base);
- base_ = new_base;
- curr_ = p_.display[0]->leaf().begin();
- }
- }
-
- void decrement()
- {
- assert(i_ > 0);
- --i_;
- if (i_ >= base_) {
- --curr_;
- } else {
- auto new_base = base_ - branches<B>;
- p_.goto_pos(new_base, base_ ^ new_base);
- base_ = new_base;
- curr_ = std::prev(p_.display[0]->leaf().end());
- }
- }
-
- void advance(std::ptrdiff_t n)
- {
- i_ += n;
- if (i_ <= base_ && i_ - base_ < branches<B>) {
- curr_ += n;
- } else {
- auto new_base = i_ & ~mask<B>;
- p_.goto_pos(new_base, base_ ^ new_base);
- base_ = new_base;
- curr_ = p_.display[0]->leaf().begin() + (i_ - base_);
- }
- }
-
- bool equal(const iterator& other) const { return i_ == other.i_; }
-
- std::ptrdiff_t distance_to(const iterator& other) const
- {
- return other.i_ > i_ ? static_cast<std::ptrdiff_t>(other.i_ - i_)
- : -static_cast<std::ptrdiff_t>(i_ - other.i_);
- }
-
- const T& dereference() const { return *curr_; }
-};
-
-} /* namespace dvektor */
-} /* namespace detail */
-} /* namespace immer */
diff --git a/src/third_party/immer/dist/immer/experimental/dvektor.hpp b/src/third_party/immer/dist/immer/experimental/dvektor.hpp
deleted file mode 100644
index a4227d6498f..00000000000
--- a/src/third_party/immer/dist/immer/experimental/dvektor.hpp
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/experimental/detail/dvektor_impl.hpp>
-
-#include <immer/memory_policy.hpp>
-
-#include <cstddef>
-
-namespace immer {
-
-template <typename T, int B = 5, typename MemoryPolicy = default_memory_policy>
-class dvektor
-{
- using impl_t = detail::dvektor::impl<T, B, MemoryPolicy>;
-
-public:
- using value_type = T;
- using reference = const T&;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = detail::dvektor::iterator<T, B, MemoryPolicy>;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- dvektor() = default;
-
- iterator begin() const { return {impl_}; }
- iterator end() const { return {impl_, typename iterator::end_t{}}; }
-
- reverse_iterator rbegin() const { return reverse_iterator{end()}; }
- reverse_iterator rend() const { return reverse_iterator{begin()}; }
-
- std::size_t size() const { return impl_.size; }
- bool empty() const { return impl_.size == 0; }
-
- reference operator[](size_type index) const { return impl_.get(index); }
-
- dvektor push_back(value_type value) const
- {
- return {impl_.push_back(std::move(value))};
- }
-
- dvektor assoc(std::size_t idx, value_type value) const
- {
- return {impl_.assoc(idx, std::move(value))};
- }
-
- template <typename FnT>
- dvektor update(std::size_t idx, FnT&& fn) const
- {
- return {impl_.update(idx, std::forward<FnT>(fn))};
- }
-
-private:
- dvektor(impl_t impl)
- : impl_(std::move(impl))
- {}
- impl_t impl_ = detail::dvektor::empty<T, B, MemoryPolicy>;
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/flex_vector.hpp b/src/third_party/immer/dist/immer/flex_vector.hpp
deleted file mode 100644
index f970db910a5..00000000000
--- a/src/third_party/immer/dist/immer/flex_vector.hpp
+++ /dev/null
@@ -1,624 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/rbts/rrbtree.hpp>
-#include <immer/detail/rbts/rrbtree_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-namespace immer {
-
-template <typename T,
- typename MP,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class vector;
-
-template <typename T,
- typename MP,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class flex_vector_transient;
-
-/*!
- * Immutable sequential container supporting both random access,
- * structural sharing and efficient concatenation and slicing.
- *
- * @tparam T The type of the values to be stored in the container.
- * @tparam MemoryPolicy Memory management policy. See @ref
- * memory_policy.
- *
- * @rst
- *
- * This container is very similar to `vector`_ but also supports
- * :math:`O(log(size))` *concatenation*, *slicing* and *insertion* at
- * any point. Its performance characteristics are almost identical
- * until one of these operations is performed. After that,
- * performance is degraded by a constant factor that usually oscilates
- * in the range :math:`[1, 2)` depending on the operation and the
- * amount of flexible operations that have been performed.
- *
- * .. tip:: A `vector`_ can be converted to a `flex_vector`_ in
- * constant time without any allocation. This is so because the
- * internal structure of a *vector* is a strict subset of the
- * internal structure of a *flexible vector*. You can take
- * advantage of this property by creating normal vectors as long as
- * the flexible operations are not needed, and convert later in
- * your processing pipeline once and if these are needed.
- *
- * @endrst
- */
-template <typename T,
- typename MemoryPolicy = default_memory_policy,
- detail::rbts::bits_t B = default_bits,
- detail::rbts::bits_t BL =
- detail::rbts::derive_bits_leaf<T, MemoryPolicy, B>>
-class flex_vector
-{
- using impl_t = detail::rbts::rrbtree<T, MemoryPolicy, B, BL>;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
-public:
- static constexpr auto bits = B;
- static constexpr auto bits_leaf = BL;
- using memory_policy = MemoryPolicy;
-
- using value_type = T;
- using reference = const T&;
- using size_type = detail::rbts::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = detail::rbts::rrbtree_iterator<T, MemoryPolicy, B, BL>;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using transient_type = flex_vector_transient<T, MemoryPolicy, B, BL>;
-
- /*!
- * Returns the maximum theoretical size supported by the internal structure
- * given the current B, BL.
- */
- constexpr static size_type max_size() { return impl_t::max_size(); }
-
- /*!
- * Default constructor. It creates a flex_vector of `size() == 0`.
- * It does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- flex_vector() = default;
-
- /*!
- * Constructs a flex_vector containing the elements in `values`.
- */
- flex_vector(std::initializer_list<T> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a flex_vector containing the elements in the range
- * defined by the input iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- flex_vector(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Constructs a vector containing the element `val` repeated `n`
- * times.
- */
- flex_vector(size_type n, T v = {})
- : impl_{impl_t::from_fill(n, v)}
- {}
-
- /*!
- * Default constructor. It creates a flex_vector with the same
- * contents as `v`. It does not allocate memory and is
- * @f$ O(1) @f$.
- */
- flex_vector(vector<T, MemoryPolicy, B, BL> v)
- : impl_{v.impl_.size,
- v.impl_.shift,
- v.impl_.root->inc(),
- v.impl_.tail->inc()}
- {}
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Access the last element.
- */
- IMMER_NODISCARD const T& back() const { return impl_.back(); }
-
- /*!
- * Access the first element.
- */
- IMMER_NODISCARD const T& front() const { return impl_.front(); }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ 0 index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- IMMER_NODISCARD reference operator[](size_type index) const
- {
- return impl_.get(index);
- }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Returns whether the vectors are equal.
- */
- IMMER_NODISCARD bool operator==(const flex_vector& other) const
- {
- return impl_.equals(other.impl_);
- }
- IMMER_NODISCARD bool operator!=(const flex_vector& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns a flex_vector with `value` inserted at the end. It may
- * allocate memory and its complexity is *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: push-back/start
- * :end-before: push-back/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector push_back(value_type value) const&
- {
- return impl_.push_back(std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) push_back(value_type value) &&
- {
- return push_back_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns a flex_vector with `value` inserted at the front. It may
- * allocate memory and its complexity is @f$ O(log(size)) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: push-front/start
- * :end-before: push-front/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector push_front(value_type value) const
- {
- return flex_vector{}.push_back(value) + *this;
- }
-
- /*!
- * Returns a flex_vector containing value `value` at position `index`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: set/start
- * :end-before: set/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector set(size_type index, value_type value) const&
- {
- return impl_.assoc(index, std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) set(size_type index, value_type value) &&
- {
- return set_move(move_t{}, index, std::move(value));
- }
-
- /*!
- * Returns a vector containing the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: update/start
- * :end-before: update/end
- *
- * @endrst
-
- */
- template <typename FnT>
- IMMER_NODISCARD flex_vector update(size_type index, FnT&& fn) const&
- {
- return impl_.update(index, std::forward<FnT>(fn));
- }
-
- template <typename FnT>
- IMMER_NODISCARD decltype(auto) update(size_type index, FnT&& fn) &&
- {
- return update_move(move_t{}, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Returns a vector containing only the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: take/start
- * :end-before: take/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector take(size_type elems) const&
- {
- return impl_.take(elems);
- }
-
- IMMER_NODISCARD decltype(auto) take(size_type elems) &&
- {
- return take_move(move_t{}, elems);
- }
-
- /*!
- * Returns a vector without the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: drop/start
- * :end-before: drop/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector drop(size_type elems) const&
- {
- return impl_.drop(elems);
- }
-
- IMMER_NODISCARD decltype(auto) drop(size_type elems) &&
- {
- return drop_move(move_t{}, elems);
- }
-
- /*!
- * Concatenation operator. Returns a flex_vector with the contents
- * of `l` followed by those of `r`. It may allocate memory
- * and its complexity is @f$ O(log(max(size_r, size_l))) @f$
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: concat/start
- * :end-before: concat/end
- *
- * @endrst
- */
- IMMER_NODISCARD friend flex_vector operator+(const flex_vector& l,
- const flex_vector& r)
- {
- return l.impl_.concat(r.impl_);
- }
-
- IMMER_NODISCARD friend decltype(auto) operator+(flex_vector&& l,
- const flex_vector& r)
- {
- return concat_move(move_t{}, std::move(l), r);
- }
-
- IMMER_NODISCARD friend decltype(auto) operator+(const flex_vector& l,
- flex_vector&& r)
- {
- return concat_move(move_t{}, l, std::move(r));
- }
-
- IMMER_NODISCARD friend decltype(auto) operator+(flex_vector&& l,
- flex_vector&& r)
- {
- return concat_move(move_t{}, std::move(l), std::move(r));
- }
-
- /*!
- * Returns a flex_vector with the `value` inserted at index
- * `pos`. It may allocate memory and its complexity is @f$
- * O(log(size)) @f$
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: insert/start
- * :end-before: insert/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector insert(size_type pos, T value) const&
- {
- return take(pos).push_back(std::move(value)) + drop(pos);
- }
- IMMER_NODISCARD decltype(auto) insert(size_type pos, T value) &&
- {
- using std::move;
- auto rs = drop(pos);
- return std::move(*this).take(pos).push_back(std::move(value)) +
- std::move(rs);
- }
-
- IMMER_NODISCARD flex_vector insert(size_type pos, flex_vector value) const&
- {
- return take(pos) + std::move(value) + drop(pos);
- }
- IMMER_NODISCARD decltype(auto) insert(size_type pos, flex_vector value) &&
- {
- using std::move;
- auto rs = drop(pos);
- return std::move(*this).take(pos) + std::move(value) + std::move(rs);
- }
-
- /*!
- * Returns a flex_vector without the element at index `pos`. It
- * may allocate memory and its complexity is @f$ O(log(size)) @f$
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/flex-vector/flex-vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: erase/start
- * :end-before: erase/end
- *
- * @endrst
- */
- IMMER_NODISCARD flex_vector erase(size_type pos) const&
- {
- return take(pos) + drop(pos + 1);
- }
- IMMER_NODISCARD decltype(auto) erase(size_type pos) &&
- {
- auto rs = drop(pos + 1);
- return std::move(*this).take(pos) + std::move(rs);
- }
-
- IMMER_NODISCARD flex_vector erase(size_type pos, size_type lpos) const&
- {
- return lpos > pos ? take(pos) + drop(lpos) : *this;
- }
- IMMER_NODISCARD decltype(auto) erase(size_type pos, size_type lpos) &&
- {
- if (lpos > pos) {
- auto rs = drop(lpos);
- return std::move(*this).take(pos) + std::move(rs);
- } else {
- return std::move(*this);
- }
- }
-
- /*!
- * Returns an @a transient form of this container, an
- * `immer::flex_vector_transient`.
- */
- IMMER_NODISCARD transient_type transient() const& { return impl_; }
- IMMER_NODISCARD transient_type transient() && { return std::move(impl_); }
-
- /*!
- * Returns a value that can be used as identity for the container. If two
- * values have the same identity, they are guaranteed to be equal and to
- * contain the same objects. However, two equal containers are not
- * guaranteed to have the same identity.
- */
- std::pair<void*, void*> identity() const
- {
- return {impl_.root, impl_.tail};
- }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-#if IMMER_DEBUG_PRINT
- void debug_print(std::ostream& out = std::cerr) const
- {
- impl_.debug_print(out);
- }
-#endif
-
-private:
- friend transient_type;
-
- flex_vector(impl_t impl)
- : impl_(std::move(impl))
- {
-#if IMMER_DEBUG_PRINT
- // force the compiler to generate debug_print, so we can call
- // it from a debugger
- [](volatile auto) {}(&flex_vector::debug_print);
-#endif
- }
-
- flex_vector&& push_back_move(std::true_type, value_type value)
- {
- impl_.push_back_mut({}, std::move(value));
- return std::move(*this);
- }
- flex_vector push_back_move(std::false_type, value_type value)
- {
- return impl_.push_back(std::move(value));
- }
-
- flex_vector&& set_move(std::true_type, size_type index, value_type value)
- {
- impl_.assoc_mut({}, index, std::move(value));
- return std::move(*this);
- }
- flex_vector set_move(std::false_type, size_type index, value_type value)
- {
- return impl_.assoc(index, std::move(value));
- }
-
- template <typename Fn>
- flex_vector&& update_move(std::true_type, size_type index, Fn&& fn)
- {
- impl_.update_mut({}, index, std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- flex_vector update_move(std::false_type, size_type index, Fn&& fn)
- {
- return impl_.update(index, std::forward<Fn>(fn));
- }
-
- flex_vector&& take_move(std::true_type, size_type elems)
- {
- impl_.take_mut({}, elems);
- return std::move(*this);
- }
- flex_vector take_move(std::false_type, size_type elems)
- {
- return impl_.take(elems);
- }
-
- flex_vector&& drop_move(std::true_type, size_type elems)
- {
- impl_.drop_mut({}, elems);
- return std::move(*this);
- }
- flex_vector drop_move(std::false_type, size_type elems)
- {
- return impl_.drop(elems);
- }
-
- static flex_vector&&
- concat_move(std::true_type, flex_vector&& l, const flex_vector& r)
- {
- concat_mut_l(l.impl_, {}, r.impl_);
- return std::move(l);
- }
- static flex_vector&&
- concat_move(std::true_type, const flex_vector& l, flex_vector&& r)
- {
- concat_mut_r(l.impl_, r.impl_, {});
- return std::move(r);
- }
- static flex_vector&&
- concat_move(std::true_type, flex_vector&& l, flex_vector&& r)
- {
- concat_mut_lr_l(l.impl_, {}, r.impl_, {});
- return std::move(l);
- }
- static flex_vector
- concat_move(std::false_type, const flex_vector& l, const flex_vector& r)
- {
- return l.impl_.concat(r.impl_);
- }
-
- impl_t impl_ = {};
-};
-
-static_assert(std::is_nothrow_move_constructible<flex_vector<int>>::value,
- "flex_vector is not nothrow move constructible");
-static_assert(std::is_nothrow_move_assignable<flex_vector<int>>::value,
- "flex_vector is not nothrow move assignable");
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/flex_vector_transient.hpp b/src/third_party/immer/dist/immer/flex_vector_transient.hpp
deleted file mode 100644
index 5c419ae02bd..00000000000
--- a/src/third_party/immer/dist/immer/flex_vector_transient.hpp
+++ /dev/null
@@ -1,248 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/rbts/rrbtree.hpp>
-#include <immer/detail/rbts/rrbtree_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-namespace immer {
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class flex_vector;
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class vector_transient;
-
-/*!
- * Mutable version of `immer::flex_vector`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename T,
- typename MemoryPolicy = default_memory_policy,
- detail::rbts::bits_t B = default_bits,
- detail::rbts::bits_t BL =
- detail::rbts::derive_bits_leaf<T, MemoryPolicy, B>>
-class flex_vector_transient : MemoryPolicy::transience_t::owner
-{
- using impl_t = detail::rbts::rrbtree<T, MemoryPolicy, B, BL>;
- using base_t = typename MemoryPolicy::transience_t::owner;
- using owner_t = typename MemoryPolicy::transience_t::owner;
-
-public:
- static constexpr auto bits = B;
- static constexpr auto bits_leaf = BL;
- using memory_policy = MemoryPolicy;
-
- using value_type = T;
- using reference = const T&;
- using size_type = detail::rbts::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = detail::rbts::rrbtree_iterator<T, MemoryPolicy, B, BL>;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using persistent_type = flex_vector<T, MemoryPolicy, B, BL>;
-
- /*!
- * Default constructor. It creates a flex_vector of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- flex_vector_transient() = default;
-
- /*!
- * Default constructor. It creates a flex_vector with the same
- * contents as `v`. It does not allocate memory and is
- * @f$ O(1) @f$.
- */
- flex_vector_transient(vector_transient<T, MemoryPolicy, B, BL> v)
- : base_t{std::move(static_cast<base_t&>(v))}
- , impl_{v.impl_.size,
- v.impl_.shift,
- v.impl_.root->inc(),
- v.impl_.tail->inc()}
- {}
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ 0 index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- reference operator[](size_type index) const { return impl_.get(index); }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Inserts `value` at the end. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- void push_back(value_type value)
- {
- impl_.push_back_mut(*this, std::move(value));
- }
-
- /*!
- * Sets to the value `value` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void set(size_type index, value_type value)
- {
- impl_.assoc_mut(*this, index, std::move(value));
- }
-
- /*!
- * Updates the vector to contain the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `0 >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- template <typename FnT>
- void update(size_type index, FnT&& fn)
- {
- impl_.update_mut(*this, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Resizes the vector to only contain the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void take(size_type elems) { impl_.take_mut(*this, elems); }
-
- /*!
- * Removes the first the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void drop(size_type elems) { impl_.drop_mut(*this, elems); }
-
- /*!
- * Appends the contents of the `r` at the end. It may allocate
- * memory and its complexity is:
- * @f$ O(log(max(size_r, size_l))) @f$
- */
- void append(flex_vector_transient& r)
- {
- r.owner_t::operator=(owner_t{});
- concat_mut_l(impl_, *this, r.impl_);
- }
- void append(flex_vector_transient&& r)
- {
- concat_mut_lr_l(impl_, *this, r.impl_, r);
- }
-
- /*!
- * Prepends the contents of the `l` at the beginning. It may
- * allocate memory and its complexity is:
- * @f$ O(log(max(size_r, size_l))) @f$
- */
- void prepend(flex_vector_transient& l)
- {
- l.owner_t::operator=(owner_t{});
- concat_mut_r(l.impl_, impl_, *this);
- }
- void prepend(flex_vector_transient&& l)
- {
- concat_mut_lr_r(l.impl_, l, impl_, *this);
- }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::flex_vector`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return impl_;
- }
- IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
-
-private:
- friend persistent_type;
-
- flex_vector_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = {};
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/cpp_heap.hpp b/src/third_party/immer/dist/immer/heap/cpp_heap.hpp
deleted file mode 100644
index 119fceecb4e..00000000000
--- a/src/third_party/immer/dist/immer/heap/cpp_heap.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstddef>
-#include <memory>
-
-namespace immer {
-
-/*!
- * A heap that uses `operator new` and `operator delete`.
- */
-struct cpp_heap
-{
- /*!
- * Returns a pointer to a memory region of size `size`, if the
- * allocation was successful, and throws otherwise.
- */
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags...)
- {
- return ::operator new(size);
- }
-
- /*!
- * Releases a memory region `data` that was previously returned by
- * `allocate`. One must not use nor deallocate again a memory
- * region that once it has been deallocated.
- */
- static void deallocate(std::size_t size, void* data)
- {
- ::operator delete(data);
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/debug_size_heap.hpp b/src/third_party/immer/dist/immer/heap/debug_size_heap.hpp
deleted file mode 100644
index d5288c646f8..00000000000
--- a/src/third_party/immer/dist/immer/heap/debug_size_heap.hpp
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/heap/identity_heap.hpp>
-
-#include <cassert>
-#include <cstddef>
-#include <type_traits>
-#include <memory>
-
-namespace immer {
-
-#if IMMER_ENABLE_DEBUG_SIZE_HEAP
-
-/*!
- * A heap that in debug mode ensures that the sizes for allocation and
- * deallocation do match.
- */
-template <typename Base>
-struct debug_size_heap
-{
-#if defined(__MINGW32__) && !defined(__MINGW64__)
- // There is a bug in MinGW 32bit:
- // https://sourceforge.net/p/mingw-w64/bugs/778/ It causes different
- // versions of std::max_align_t to be defined, depending on inclusion order
- // of stddef.h and stdint.h. As we have no control over the inclusion order
- // here (as it might be set in stone by the outside world), we can't easily
- // pin it to one of both versions of std::max_align_t. This means, we have
- // to hardcode extra_size for MinGW 32bit builds until the mentioned bug is
- // fixed.
- constexpr static auto extra_size = 8;
-#else
- constexpr static auto extra_size = sizeof(
- std::aligned_storage_t<sizeof(std::size_t), alignof(std::max_align_t)>);
-#endif
-
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags... tags)
- {
- auto p = (std::size_t*) Base::allocate(size + extra_size, tags...);
- new (p) std::size_t{size};
- return ((char*) p) + extra_size;
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* data, Tags... tags)
- {
- auto p = (std::size_t*) (((char*) data) - extra_size);
- assert(*p == size);
- Base::deallocate(size + extra_size, p, tags...);
- }
-};
-
-#else // IMMER_ENABLE_DEBUG_SIZE_HEAP
-
-template <typename Base>
-using debug_size_heap = identity_heap<Base>;
-
-#endif // !IMMER_ENABLE_DEBUG_SIZE_HEAP
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/free_list_heap.hpp b/src/third_party/immer/dist/immer/heap/free_list_heap.hpp
deleted file mode 100644
index 15ae01d60fe..00000000000
--- a/src/third_party/immer/dist/immer/heap/free_list_heap.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/free_list_node.hpp>
-#include <immer/heap/with_data.hpp>
-
-#include <atomic>
-#include <cassert>
-#include <cstddef>
-
-namespace immer {
-
-/*!
- * Adaptor that does not release the memory to the parent heap but
- * instead it keeps the memory in a thread-safe global free list. Must
- * be preceded by a `with_data<free_list_node, ...>` heap adaptor.
- *
- * @tparam Size Maximum size of the objects to be allocated.
- * @tparam Base Type of the parent heap.
- */
-template <std::size_t Size, std::size_t Limit, typename Base>
-struct free_list_heap : Base
-{
- using base_t = Base;
-
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags...)
- {
- assert(size <= sizeof(free_list_node) + Size);
- assert(size >= sizeof(free_list_node));
-
- free_list_node* n;
- do {
- n = head().data;
- if (!n) {
- auto p = base_t::allocate(Size + sizeof(free_list_node));
- return static_cast<free_list_node*>(p);
- }
- } while (!head().data.compare_exchange_weak(n, n->next));
- head().count.fetch_sub(1u, std::memory_order_relaxed);
- return n;
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* data, Tags...)
- {
- assert(size <= sizeof(free_list_node) + Size);
- assert(size >= sizeof(free_list_node));
-
- // we use relaxed, because we are fine with temporarily having
- // a few more/less buffers in free list
- if (head().count.load(std::memory_order_relaxed) >= Limit) {
- base_t::deallocate(Size + sizeof(free_list_node), data);
- } else {
- auto n = static_cast<free_list_node*>(data);
- do {
- n->next = head().data;
- } while (!head().data.compare_exchange_weak(n->next, n));
- head().count.fetch_add(1u, std::memory_order_relaxed);
- }
- }
-
-private:
- struct head_t
- {
- std::atomic<free_list_node*> data;
- std::atomic<std::size_t> count;
- };
-
- static head_t& head()
- {
- static head_t head_{{nullptr}, {0}};
- return head_;
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/free_list_node.hpp b/src/third_party/immer/dist/immer/heap/free_list_node.hpp
deleted file mode 100644
index acab4779aa4..00000000000
--- a/src/third_party/immer/dist/immer/heap/free_list_node.hpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/with_data.hpp>
-
-namespace immer {
-
-struct free_list_node
-{
- free_list_node* next;
-};
-
-template <typename Base>
-struct with_free_list_node : with_data<free_list_node, Base>
-{};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/gc_heap.hpp b/src/third_party/immer/dist/immer/heap/gc_heap.hpp
deleted file mode 100644
index 8fc7754e5e6..00000000000
--- a/src/third_party/immer/dist/immer/heap/gc_heap.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/heap/tags.hpp>
-
-#if IMMER_HAS_LIBGC
-#include <gc/gc.h>
-#else
-#error "Using garbage collection requires libgc"
-#endif
-
-#include <cassert>
-#include <cstdlib>
-#include <exception>
-#include <memory>
-
-namespace immer {
-
-#ifdef IMMER_GC_REQUIRE_INIT
-#define IMMER_GC_REQUIRE_INIT_ IMMER_GC_REQUIRE_INIT
-#elifdef __APPLE__
-#define IMMER_GC_REQUIRE_INIT_ 1
-#else
-#define IMMER_GC_REQUIRE_INIT_ 0
-#endif
-
-#if IMMER_GC_REQUIRE_INIT_
-
-namespace detail {
-
-template <int Dummy = 0>
-struct gc_initializer
-{
- gc_initializer() { GC_INIT(); }
- static gc_initializer init;
-};
-
-template <int D>
-gc_initializer<D> gc_initializer<D>::init{};
-
-inline void gc_initializer_guard()
-{
- static gc_initializer<> init_ = gc_initializer<>::init;
- (void) init_;
-}
-
-} // namespace detail
-
-#define IMMER_GC_INIT_GUARD_ ::immer::detail::gc_initializer_guard()
-
-#else
-
-#define IMMER_GC_INIT_GUARD_
-
-#endif // IMMER_GC_REQUIRE_INIT_
-
-/*!
- * Heap that uses a tracing garbage collector.
- *
- * @rst
- *
- * This heap uses the `Boehm's conservative garbage collector`_ under
- * the hood. This is a tracing garbage collector that automatically
- * reclaims unused memory. Thus, it is not needed to call
- * ``deallocate()`` in order to release memory.
- *
- * .. admonition:: Dependencies
- * :class: tip
- *
- * In order to use this header file, you need to make sure that
- * Boehm's ``libgc`` is your include path and link to its binary
- * library.
- *
- * .. caution:: Memory that is allocated with the standard ``malloc``
- * and ``free`` is not visible to ``libgc`` when it is looking for
- * references. This means that if, let's say, you store a
- * :cpp:class:`immer::vector` using a ``gc_heap`` inside a
- * ``std::vector`` that uses a standard allocator, the memory of
- * the former might be released automatically at unexpected times
- * causing crashes.
- *
- * .. caution:: When using a ``gc_heap`` in combination with immutable
- * containers, the destructors of the contained objects will never
- * be called. It is ok to store containers inside containers as
- * long as all of them use a ``gc_heap`` consistently, but storing
- * other kinds of objects with relevant destructors
- * (e.g. containers with reference counting or other kinds of
- * *resource handles*) might cause memory leaks and other problems.
- *
- * .. _boehm's conservative garbage collector: https://github.com/ivmai/bdwgc
- *
- * @endrst
- */
-class gc_heap
-{
-public:
- static void* allocate(std::size_t n)
- {
- IMMER_GC_INIT_GUARD_;
- auto p = GC_malloc(n);
- if (IMMER_UNLIKELY(!p))
- IMMER_THROW(std::bad_alloc{});
- return p;
- }
-
- static void* allocate(std::size_t n, norefs_tag)
- {
- IMMER_GC_INIT_GUARD_;
- auto p = GC_malloc_atomic(n);
- if (IMMER_UNLIKELY(!p))
- IMMER_THROW(std::bad_alloc{});
- return p;
- }
-
- static void deallocate(std::size_t, void* data) { GC_free(data); }
-
- static void deallocate(std::size_t, void* data, norefs_tag)
- {
- GC_free(data);
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/heap_policy.hpp b/src/third_party/immer/dist/immer/heap/heap_policy.hpp
deleted file mode 100644
index 1a858c5e124..00000000000
--- a/src/third_party/immer/dist/immer/heap/heap_policy.hpp
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/heap/debug_size_heap.hpp>
-#include <immer/heap/free_list_heap.hpp>
-#include <immer/heap/split_heap.hpp>
-#include <immer/heap/thread_local_free_list_heap.hpp>
-
-#include <algorithm>
-#include <cstdlib>
-
-namespace immer {
-
-/*!
- * Heap policy that unconditionally uses its `Heap` argument.
- */
-template <typename Heap>
-struct heap_policy
-{
- using type = Heap;
-
- template <std::size_t>
- struct optimized
- {
- using type = Heap;
- };
-};
-
-template <typename Deriv, typename HeapPolicy>
-struct enable_optimized_heap_policy
-{
- static void* operator new(std::size_t size)
- {
- using heap_type =
- typename HeapPolicy ::template optimized<sizeof(Deriv)>::type;
-
- return heap_type::allocate(size);
- }
-
- static void operator delete(void* data, std::size_t size)
- {
- using heap_type =
- typename HeapPolicy ::template optimized<sizeof(Deriv)>::type;
-
- heap_type::deallocate(size, data);
- }
-};
-
-/*!
- * Heap policy that returns a heap with a free list of objects
- * of `max_size = max(Sizes...)` on top an underlying `Heap`. Note
- * these two properties of the resulting heap:
- *
- * - Allocating an object that is bigger than `max_size` may trigger
- * *undefined behavior*.
- *
- * - Allocating an object of size less than `max_size` still
- * returns an object of `max_size`.
- *
- * Basically, this heap will always return objects of `max_size`.
- * When an object is freed, it does not directly invoke `std::free`,
- * but it keeps the object in a global linked list instead. When a
- * new object is requested, it does not need to call `std::malloc` but
- * it can directly pop and return the other object from the global
- * list, a much faster operation.
- *
- * This actually creates a hierarchy with two free lists:
- *
- * - A `thread_local` free list is used first. It does not need any
- * kind of synchronization and is very fast. When the thread
- * finishes, its contents are returned to the next free list.
- *
- * - A global free list using lock-free access via atomics.
- *
- * @tparam Heap Heap to be used when the free list is empty.
- *
- * @rst
- *
- * .. tip:: For many applications that use immutable data structures
- * significantly, this is actually the best heap policy.
- *
- * Note that most our data structures internally use trees with the
- * same big branching factors. This means that all *vectors*,
- * *maps*, etc. can just allocate elements from the same free-list
- * optimized heap. Not only does this lowers the allocation time,
- * but also makes up for more efficient *cache utilization*. When
- * a new node is needed, there are high chances the allocator will
- * return a node that was just accessed. When batches of immutable
- * updates are made, this can make a significant difference.
- *
- * @endrst
- */
-template <typename Heap, std::size_t Limit = default_free_list_size>
-struct free_list_heap_policy
-{
- using type = debug_size_heap<Heap>;
-
- template <std::size_t Size>
- struct optimized
- {
- using type =
- split_heap<Size,
- with_free_list_node<thread_local_free_list_heap<
- Size,
- Limit,
- free_list_heap<Size, Limit, debug_size_heap<Heap>>>>,
- debug_size_heap<Heap>>;
- };
-};
-
-/*!
- * Similar to @ref free_list_heap_policy, but it assumes no
- * multi-threading, so a single global free list with no concurrency
- * checks is used.
- */
-template <typename Heap, std::size_t Limit = default_free_list_size>
-struct unsafe_free_list_heap_policy
-{
- using type = Heap;
-
- template <std::size_t Size>
- struct optimized
- {
- using type = split_heap<
- Size,
- with_free_list_node<
- unsafe_free_list_heap<Size, Limit, debug_size_heap<Heap>>>,
- debug_size_heap<Heap>>;
- };
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/identity_heap.hpp b/src/third_party/immer/dist/immer/heap/identity_heap.hpp
deleted file mode 100644
index 032cb3f221d..00000000000
--- a/src/third_party/immer/dist/immer/heap/identity_heap.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstdlib>
-
-namespace immer {
-
-/*!
- * A heap that simply passes on to the parent heap.
- */
-template <typename Base>
-struct identity_heap : Base
-{
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags... tags)
- {
- return Base::allocate(size, tags...);
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* data, Tags... tags)
- {
- Base::deallocate(size, data, tags...);
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/malloc_heap.hpp b/src/third_party/immer/dist/immer/heap/malloc_heap.hpp
deleted file mode 100644
index af9e983fae7..00000000000
--- a/src/third_party/immer/dist/immer/heap/malloc_heap.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-
-#include <cassert>
-#include <cstdlib>
-#include <exception>
-#include <memory>
-
-namespace immer {
-
-/*!
- * A heap that uses `std::malloc` and `std::free` to manage memory.
- */
-struct malloc_heap
-{
- /*!
- * Returns a pointer to a memory region of size `size`, if the
- * allocation was successful and throws `std::bad_alloc` otherwise.
- */
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags...)
- {
- auto p = std::malloc(size);
- if (IMMER_UNLIKELY(!p))
- IMMER_THROW(std::bad_alloc{});
- return p;
- }
-
- /*!
- * Releases a memory region `data` that was previously returned by
- * `allocate`. One must not use nor deallocate again a memory
- * region that once it has been deallocated.
- */
- static void deallocate(std::size_t, void* data) { std::free(data); }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/split_heap.hpp b/src/third_party/immer/dist/immer/heap/split_heap.hpp
deleted file mode 100644
index 18ae684bfd2..00000000000
--- a/src/third_party/immer/dist/immer/heap/split_heap.hpp
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <atomic>
-#include <cassert>
-#include <cstddef>
-
-namespace immer {
-
-/*!
- * Adaptor that uses `SmallHeap` for allocations that are smaller or
- * equal to `Size` and `BigHeap` otherwise.
- */
-template <std::size_t Size, typename SmallHeap, typename BigHeap>
-struct split_heap
-{
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags... tags)
- {
- return size <= Size ? SmallHeap::allocate(size, tags...)
- : BigHeap::allocate(size, tags...);
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* data, Tags... tags)
- {
- if (size <= Size)
- SmallHeap::deallocate(size, data, tags...);
- else
- BigHeap::deallocate(size, data, tags...);
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/tags.hpp b/src/third_party/immer/dist/immer/heap/tags.hpp
deleted file mode 100644
index d1ce48d05c8..00000000000
--- a/src/third_party/immer/dist/immer/heap/tags.hpp
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-namespace immer {
-
-struct norefs_tag
-{};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/thread_local_free_list_heap.hpp b/src/third_party/immer/dist/immer/heap/thread_local_free_list_heap.hpp
deleted file mode 100644
index b97a7f50829..00000000000
--- a/src/third_party/immer/dist/immer/heap/thread_local_free_list_heap.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/unsafe_free_list_heap.hpp>
-
-#include <cstddef>
-
-namespace immer {
-namespace detail {
-
-template <typename Heap>
-struct thread_local_free_list_storage
-{
- struct head_t
- {
- free_list_node* data;
- std::size_t count;
-
- ~head_t() { Heap::clear(); }
- };
-
- static head_t& head()
- {
- thread_local static head_t head_{nullptr, 0};
- return head_;
- }
-};
-
-} // namespace detail
-
-/*!
- * Adaptor that does not release the memory to the parent heap but
- * instead it keeps the memory in a `thread_local` global free
- * list. Must be preceded by a `with_data<free_list_node, ...>` heap
- * adaptor. When the current thread finishes, the memory is returned
- * to the parent heap.
- *
- * @tparam Size Maximum size of the objects to be allocated.
- * @tparam Limit Maximum number of elements to keep in the free list.
- * @tparam Base Type of the parent heap.
- */
-template <std::size_t Size, std::size_t Limit, typename Base>
-struct thread_local_free_list_heap
- : detail::unsafe_free_list_heap_impl<detail::thread_local_free_list_storage,
- Size,
- Limit,
- Base>
-{};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/unsafe_free_list_heap.hpp b/src/third_party/immer/dist/immer/heap/unsafe_free_list_heap.hpp
deleted file mode 100644
index 9b41dfcb371..00000000000
--- a/src/third_party/immer/dist/immer/heap/unsafe_free_list_heap.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/heap/free_list_node.hpp>
-
-#include <cassert>
-#include <cstddef>
-
-namespace immer {
-namespace detail {
-
-template <typename Heap>
-struct unsafe_free_list_storage
-{
- struct head_t
- {
- free_list_node* data;
- std::size_t count;
- };
-
- static head_t& head()
- {
- static head_t head_{nullptr, 0};
- return head_;
- }
-};
-
-template <template <class> class Storage,
- std::size_t Size,
- std::size_t Limit,
- typename Base>
-class unsafe_free_list_heap_impl : Base
-{
- using storage = Storage<unsafe_free_list_heap_impl>;
-
-public:
- using base_t = Base;
-
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags...)
- {
- assert(size <= sizeof(free_list_node) + Size);
- assert(size >= sizeof(free_list_node));
-
- auto n = storage::head().data;
- if (!n) {
- auto p = base_t::allocate(Size + sizeof(free_list_node));
- return static_cast<free_list_node*>(p);
- }
- --storage::head().count;
- storage::head().data = n->next;
- return n;
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* data, Tags...)
- {
- assert(size <= sizeof(free_list_node) + Size);
- assert(size >= sizeof(free_list_node));
-
- if (storage::head().count >= Limit)
- base_t::deallocate(Size + sizeof(free_list_node), data);
- else {
- auto n = static_cast<free_list_node*>(data);
- n->next = storage::head().data;
- storage::head().data = n;
- ++storage::head().count;
- }
- }
-
- static void clear()
- {
- while (storage::head().data) {
- auto n = storage::head().data->next;
- base_t::deallocate(Size + sizeof(free_list_node),
- storage::head().data);
- storage::head().data = n;
- --storage::head().count;
- }
- }
-};
-
-} // namespace detail
-
-/*!
- * Adaptor that does not release the memory to the parent heap but
- * instead it keeps the memory in a global free list that **is not
- * thread-safe**. Must be preceded by a `with_data<free_list_node,
- * ...>` heap adaptor.
- *
- * @tparam Size Maximum size of the objects to be allocated.
- * @tparam Limit Maximum number of elements to keep in the free list.
- * @tparam Base Type of the parent heap.
- */
-template <std::size_t Size, std::size_t Limit, typename Base>
-struct unsafe_free_list_heap
- : detail::unsafe_free_list_heap_impl<detail::unsafe_free_list_storage,
- Size,
- Limit,
- Base>
-{};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/heap/with_data.hpp b/src/third_party/immer/dist/immer/heap/with_data.hpp
deleted file mode 100644
index 1e8c2abb082..00000000000
--- a/src/third_party/immer/dist/immer/heap/with_data.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <cstdio>
-
-namespace immer {
-
-/*!
- * Appends a default constructed extra object of type `T` at the
- * *before* the requested region.
- *
- * @tparam T Type of the appended data.
- * @tparam Base Type of the parent heap.
- */
-template <typename T, typename Base>
-struct with_data : Base
-{
- using base_t = Base;
-
- template <typename... Tags>
- static void* allocate(std::size_t size, Tags... tags)
- {
- auto p = base_t::allocate(size + sizeof(T), tags...);
- return new (p) T{} + 1;
- }
-
- template <typename... Tags>
- static void deallocate(std::size_t size, void* p, Tags... tags)
- {
- auto dp = static_cast<T*>(p) - 1;
- dp->~T();
- base_t::deallocate(size + sizeof(T), dp, tags...);
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/lock/no_lock_policy.hpp b/src/third_party/immer/dist/immer/lock/no_lock_policy.hpp
deleted file mode 100644
index 6374699065a..00000000000
--- a/src/third_party/immer/dist/immer/lock/no_lock_policy.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-namespace immer {
-
-struct no_lock_policy
-{
- bool try_lock() { return true; }
- void lock() {}
- void unlock() {}
-
- struct scoped_lock
- {
- scoped_lock(no_lock_policy&) {}
- };
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/lock/spinlock_policy.hpp b/src/third_party/immer/dist/immer/lock/spinlock_policy.hpp
deleted file mode 100644
index cebe8a533c6..00000000000
--- a/src/third_party/immer/dist/immer/lock/spinlock_policy.hpp
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <atomic>
-#include <thread>
-
-// This has been shamelessly copied from boost...
-#if defined(_MSC_VER) && _MSC_VER >= 1310 && \
- (defined(_M_IX86) || defined(_M_X64)) && !defined(__c2__)
-extern "C" void _mm_pause();
-#define IMMER_SMT_PAUSE _mm_pause()
-#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define IMMER_SMT_PAUSE __asm__ __volatile__("rep; nop" : : : "memory")
-#endif
-
-namespace immer {
-
-// This is an atomic spinlock similar to the one used by boost to provide
-// "atomic" shared_ptr operations. It also does not differ much from the one
-// from libc++ or libstdc++...
-struct spinlock_policy
-{
- std::atomic_flag v_{};
-
- bool try_lock() { return !v_.test_and_set(std::memory_order_acquire); }
-
- void lock()
- {
- for (auto k = 0u; !try_lock(); ++k) {
- if (k < 4)
- continue;
-#ifdef IMMER_SMT_PAUSE
- else if (k < 16)
- IMMER_SMT_PAUSE;
-#endif
- else
- std::this_thread::yield();
- }
- }
-
- void unlock() { v_.clear(std::memory_order_release); }
-
- struct scoped_lock
- {
- scoped_lock(const scoped_lock&) = delete;
- scoped_lock& operator=(const scoped_lock&) = delete;
-
- explicit scoped_lock(spinlock_policy& sp)
- : sp_{sp}
- {
- sp.lock();
- }
-
- ~scoped_lock() { sp_.unlock(); }
-
- private:
- spinlock_policy& sp_;
- };
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/map.hpp b/src/third_party/immer/dist/immer/map.hpp
deleted file mode 100644
index cab8e5d5d8d..00000000000
--- a/src/third_party/immer/dist/immer/map.hpp
+++ /dev/null
@@ -1,550 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/detail/hamts/champ_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <cassert>
-#include <functional>
-#include <stdexcept>
-
-namespace immer {
-
-template <typename K,
- typename T,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class map_transient;
-
-/*!
- * Immutable unordered mapping of values from type `K` to type `T`.
- *
- * @tparam K The type of the keys.
- * @tparam T The type of the values to be stored in the container.
- * @tparam Hash The type of a function object capable of hashing
- * values of type `T`.
- * @tparam Equal The type of a function object capable of comparing
- * values of type `T`.
- * @tparam MemoryPolicy Memory management policy. See @ref
- * memory_policy.
- *
- * @rst
- *
- * This container provides a good trade-off between cache locality,
- * search, update performance and structural sharing. It does so by
- * storing the data in contiguous chunks of :math:`2^{B}` elements.
- * When storing big objects, the size of these contiguous chunks can
- * become too big, damaging performance. If this is measured to be
- * problematic for a specific use-case, it can be solved by using a
- * `immer::box` to wrap the type `T`.
- *
- * **Example**
- * .. literalinclude:: ../example/map/intro.cpp
- * :language: c++
- * :start-after: intro/start
- * :end-before: intro/end
- *
- * @endrst
- *
- */
-template <typename K,
- typename T,
- typename Hash = std::hash<K>,
- typename Equal = std::equal_to<K>,
- typename MemoryPolicy = default_memory_policy,
- detail::hamts::bits_t B = default_bits>
-class map
-{
- using value_t = std::pair<K, T>;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
- struct project_value
- {
- const T& operator()(const value_t& v) const noexcept
- {
- return v.second;
- }
- T&& operator()(value_t&& v) const noexcept
- {
- return std::move(v.second);
- }
- };
-
- struct project_value_ptr
- {
- const T* operator()(const value_t& v) const noexcept
- {
- return &v.second;
- }
- };
-
- struct combine_value
- {
- template <typename Kf, typename Tf>
- value_t operator()(Kf&& k, Tf&& v) const
- {
- return {std::forward<Kf>(k), std::forward<Tf>(v)};
- }
- };
-
- struct default_value
- {
- const T& operator()() const
- {
- static T v{};
- return v;
- }
- };
-
- struct error_value
- {
- const T& operator()() const
- {
- IMMER_THROW(std::out_of_range{"key not found"});
- }
- };
-
- struct hash_key
- {
- auto operator()(const value_t& v) { return Hash{}(v.first); }
-
- template <typename Key>
- auto operator()(const Key& v)
- {
- return Hash{}(v);
- }
- };
-
- struct equal_key
- {
- auto operator()(const value_t& a, const value_t& b)
- {
- return Equal{}(a.first, b.first);
- }
-
- template <typename Key>
- auto operator()(const value_t& a, const Key& b)
- {
- return Equal{}(a.first, b);
- }
- };
-
- struct equal_value
- {
- auto operator()(const value_t& a, const value_t& b)
- {
- return Equal{}(a.first, b.first) && a.second == b.second;
- }
- };
-
- using impl_t =
- detail::hamts::champ<value_t, hash_key, equal_key, MemoryPolicy, B>;
-
-public:
- using key_type = K;
- using mapped_type = T;
- using value_type = std::pair<K, T>;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const value_type&;
- using const_reference = const value_type&;
-
- using iterator = detail::hamts::
- champ_iterator<value_t, hash_key, equal_key, MemoryPolicy, B>;
- using const_iterator = iterator;
-
- using transient_type = map_transient<K, T, Hash, Equal, MemoryPolicy, B>;
-
- using memory_policy_type = MemoryPolicy;
-
- /*!
- * Constructs a map containing the elements in `values`.
- */
- map(std::initializer_list<value_type> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a map containing the elements in the range
- * defined by the input iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- map(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Default constructor. It creates a map of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- map() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when the key `k` is contained in the map or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const Key& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns `1` when the key `k` is contained in the map or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const K& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T& operator[](const Key& k) const
- {
- return impl_.template get<project_value, default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T& operator[](const K& k) const
- {
- return impl_.template get<project_value, default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- const T& at(const Key& k) const
- {
- return impl_.template get<project_value, error_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- const T& at(const K& k) const
- {
- return impl_.template get<project_value, error_value>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`. If
- * the key is not contained in the map, a `nullptr` is returned.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * @rst
- *
- * .. admonition:: Why doesn't this function return an iterator?
- *
- * Associative containers from the C++ standard library provide a
- * ``find`` method that returns an iterator pointing to the
- * element in the container or ``end()`` when the key is missing.
- * In the case of an unordered container, the only meaningful
- * thing one may do with it is to compare it with the end, to
- * test if the find was succesfull, and dereference it. This
- * comparison is cumbersome compared to testing for a non-empty
- * optional value. Furthermore, for an immutable container,
- * returning an iterator would have some additional performance
- * cost, with no benefits otherwise.
- *
- * In our opinion, this function should return a
- * ``std::optional<const T&>`` but this construction is not valid
- * in any current standard. As a compromise we return a
- * pointer, which has similar syntactic properties yet it is
- * unfortunately unnecessarily unrestricted.
- *
- * @endrst
- */
- IMMER_NODISCARD const T* find(const K& k) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`. If
- * the key is not contained in the map, a `nullptr` is returned.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const Key& k) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Returns whether the maps are equal.
- */
- IMMER_NODISCARD bool operator==(const map& other) const
- {
- return impl_.template equals<equal_value>(other.impl_);
- }
- IMMER_NODISCARD bool operator!=(const map& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns a map containing the association `value`. If the key is
- * already in the map, it replaces its association in the map.
- * It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- IMMER_NODISCARD map insert(value_type value) const&
- {
- return impl_.add(std::move(value));
- }
- IMMER_NODISCARD decltype(auto) insert(value_type value) &&
- {
- return insert_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns a map containing the association `(k, v)`. If the key
- * is already in the map, it replaces its association in the map.
- * It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- IMMER_NODISCARD map set(key_type k, mapped_type v) const&
- {
- return impl_.add({std::move(k), std::move(v)});
- }
- IMMER_NODISCARD decltype(auto) set(key_type k, mapped_type v) &&
- {
- return set_move(move_t{}, std::move(k), std::move(v));
- }
-
- /*!
- * Returns a map replacing the association `(k, v)` by the
- * association new association `(k, fn(v))`, where `v` is the
- * currently associated value for `k` in the map or a default
- * constructed value otherwise. It may allocate memory
- * and its complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- IMMER_NODISCARD map update(key_type k, Fn&& fn) const&
- {
- return impl_
- .template update<project_value, default_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
- template <typename Fn>
- IMMER_NODISCARD decltype(auto) update(key_type k, Fn&& fn) &&
- {
- return update_move(move_t{}, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Returns a map replacing the association `(k, v)` by the association new
- * association `(k, fn(v))`, where `v` is the currently associated value for
- * `k` in the map. It does nothing if `k` is not present in the map. It
- * may allocate memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- IMMER_NODISCARD map update_if_exists(key_type k, Fn&& fn) const&
- {
- return impl_.template update_if_exists<project_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
- template <typename Fn>
- IMMER_NODISCARD decltype(auto) update_if_exists(key_type k, Fn&& fn) &&
- {
- return update_if_exists_move(
- move_t{}, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Returns a map without the key `k`. If the key is not
- * associated in the map it returns the same map. It may allocate
- * memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD map erase(const K& k) const& { return impl_.sub(k); }
- IMMER_NODISCARD decltype(auto) erase(const K& k) &&
- {
- return erase_move(move_t{}, k);
- }
-
- /*!
- * Returns a @a transient form of this container, an
- * `immer::map_transient`.
- */
- IMMER_NODISCARD transient_type transient() const&
- {
- return transient_type{impl_};
- }
- IMMER_NODISCARD transient_type transient() &&
- {
- return transient_type{std::move(impl_)};
- }
-
- /*!
- * Returns a value that can be used as identity for the container. If two
- * values have the same identity, they are guaranteed to be equal and to
- * contain the same objects. However, two equal containers are not
- * guaranteed to have the same identity.
- */
- void* identity() const { return impl_.root; }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-private:
- friend transient_type;
-
- map&& insert_move(std::true_type, value_type value)
- {
- impl_.add_mut({}, std::move(value));
- return std::move(*this);
- }
- map insert_move(std::false_type, value_type value)
- {
- return impl_.add(std::move(value));
- }
-
- map&& set_move(std::true_type, key_type k, mapped_type m)
- {
- impl_.add_mut({}, {std::move(k), std::move(m)});
- return std::move(*this);
- }
- map set_move(std::false_type, key_type k, mapped_type m)
- {
- return impl_.add({std::move(k), std::move(m)});
- }
-
- template <typename Fn>
- map&& update_move(std::true_type, key_type k, Fn&& fn)
- {
- impl_.template update_mut<project_value, default_value, combine_value>(
- {}, std::move(k), std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- map update_move(std::false_type, key_type k, Fn&& fn)
- {
- return impl_
- .template update<project_value, default_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- map&& update_if_exists_move(std::true_type, key_type k, Fn&& fn)
- {
- impl_.template update_if_exists_mut<project_value, combine_value>(
- {}, std::move(k), std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- map update_if_exists_move(std::false_type, key_type k, Fn&& fn)
- {
- return impl_.template update_if_exists<project_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
-
- map&& erase_move(std::true_type, const key_type& value)
- {
- impl_.sub_mut({}, value);
- return std::move(*this);
- }
- map erase_move(std::false_type, const key_type& value)
- {
- return impl_.sub(value);
- }
-
- map(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/map_transient.hpp b/src/third_party/immer/dist/immer/map_transient.hpp
deleted file mode 100644
index 935f48e2b07..00000000000
--- a/src/third_party/immer/dist/immer/map_transient.hpp
+++ /dev/null
@@ -1,318 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <functional>
-
-namespace immer {
-
-template <typename K,
- typename T,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class map;
-
-/*!
- * Mutable version of `immer::map`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename K,
- typename T,
- typename Hash = std::hash<K>,
- typename Equal = std::equal_to<K>,
- typename MemoryPolicy = default_memory_policy,
- detail::hamts::bits_t B = default_bits>
-class map_transient : MemoryPolicy::transience_t::owner
-{
- using base_t = typename MemoryPolicy::transience_t::owner;
- using owner_t = base_t;
-
-public:
- using persistent_type = map<K, T, Hash, Equal, MemoryPolicy, B>;
-
- using key_type = K;
- using mapped_type = T;
- using value_type = std::pair<K, T>;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const value_type&;
- using const_reference = const value_type&;
-
- using iterator = typename persistent_type::iterator;
- using const_iterator = iterator;
-
- /*!
- * Default constructor. It creates a map of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- map_transient() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when the key `k` is contained in the map or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const Key& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns `1` when the key `k` is contained in the map or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const K& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T& operator[](const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T& operator[](const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- const T& at(const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::error_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If the key is not contained in the map, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- const T& at(const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::error_value>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`. If
- * the key is not contained in the map, a `nullptr` is returned.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * @rst
- *
- * .. admonition:: Why doesn't this function return an iterator?
- *
- * Associative containers from the C++ standard library provide a
- * ``find`` method that returns an iterator pointing to the
- * element in the container or ``end()`` when the key is missing.
- * In the case of an unordered container, the only meaningful
- * thing one may do with it is to compare it with the end, to
- * test if the find was succesfull, and dereference it. This
- * comparison is cumbersome compared to testing for a non-empty
- * optional value. Furthermore, for an immutable container,
- * returning an iterator would have some additional performance
- * cost, with no benefits otherwise.
- *
- * In our opinion, this function should return a
- * ``std::optional<const T&>`` but this construction is not valid
- * in any current standard. As a compromise we return a
- * pointer, which has similar syntactic properties yet it is
- * unfortunately unnecessarily unrestricted.
- *
- * @endrst
- */
- IMMER_NODISCARD const T* find(const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`. If
- * the key is not contained in the map, a `nullptr` is returned.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Inserts the association `value`. If the key is already in the map, it
- * replaces its association in the map. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- void insert(value_type value) { impl_.add_mut(*this, std::move(value)); }
-
- /*!
- * Inserts the association `(k, v)`. If the key is already in the map, it
- * replaces its association in the map. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- void set(key_type k, mapped_type v)
- {
- impl_.add_mut(*this, {std::move(k), std::move(v)});
- }
-
- /*!
- * Replaces the association `(k, v)` by the association new association `(k,
- * fn(v))`, where `v` is the currently associated value for `k` in the map
- * or a default constructed value otherwise. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- void update(key_type k, Fn&& fn)
- {
- impl_.template update_mut<typename persistent_type::project_value,
- typename persistent_type::default_value,
- typename persistent_type::combine_value>(
- *this, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Replaces the association `(k, v)` by the association new association `(k,
- * fn(v))`, where `v` is the currently associated value for `k` in the map
- * or does nothing if `k` is not present in the map. It may allocate memory
- * and its complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- void update_if_exists(key_type k, Fn&& fn)
- {
- impl_.template update_if_exists_mut<
- typename persistent_type::project_value,
- typename persistent_type::combine_value>(
- *this, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Removes the key `k` from the k. Does nothing if the key is not
- * associated in the map. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void erase(const K& k) { impl_.sub_mut(*this, k); }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::map`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return impl_;
- }
- IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
-
-private:
- friend persistent_type;
- using impl_t = typename persistent_type::impl_t;
-
- map_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-
-public:
- // Semi-private
- const impl_t& impl() const { return impl_; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/memory_policy.hpp b/src/third_party/immer/dist/immer/memory_policy.hpp
deleted file mode 100644
index d8556b9432a..00000000000
--- a/src/third_party/immer/dist/immer/memory_policy.hpp
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/cpp_heap.hpp>
-#include <immer/heap/heap_policy.hpp>
-#include <immer/lock/no_lock_policy.hpp>
-#include <immer/lock/spinlock_policy.hpp>
-#include <immer/refcount/no_refcount_policy.hpp>
-#include <immer/refcount/refcount_policy.hpp>
-#include <immer/refcount/unsafe_refcount_policy.hpp>
-#include <immer/transience/gc_transience_policy.hpp>
-#include <immer/transience/no_transience_policy.hpp>
-#include <type_traits>
-
-namespace immer {
-
-/*!
- * Metafunction that returns the best *transience policy* to use for a
- * given *refcount policy*.
- */
-template <typename RefcountPolicy>
-struct get_transience_policy
- : std::conditional<std::is_same<RefcountPolicy, no_refcount_policy>::value,
- gc_transience_policy,
- no_transience_policy>
-{};
-
-template <typename T>
-using get_transience_policy_t = typename get_transience_policy<T>::type;
-
-/*!
- * Metafunction that returns wether to *prefer fewer bigger objects*
- * to use for a given *heap policy*.
- */
-template <typename HeapPolicy>
-struct get_prefer_fewer_bigger_objects
- : std::integral_constant<
- bool,
- std::is_same<HeapPolicy, heap_policy<cpp_heap>>::value>
-{};
-
-template <typename T>
-constexpr auto get_prefer_fewer_bigger_objects_v =
- get_prefer_fewer_bigger_objects<T>::value;
-
-/*!
- * Metafunction that returns wether to use *transient R-Values*
- * for a given *refcount policy*.
- */
-template <typename RefcountPolicy>
-struct get_use_transient_rvalues
- : std::integral_constant<
- bool,
- !std::is_same<RefcountPolicy, no_refcount_policy>::value>
-{};
-
-template <typename T>
-constexpr auto get_use_transient_rvalues_v =
- get_use_transient_rvalues<T>::value;
-
-/*!
- * This is a default implementation of a *memory policy*. A memory
- * policy is just a bag of other policies plus some flags with hints
- * to the user about the best way to use these strategies.
- *
- * @tparam HeapPolicy A *heap policy*, for example, @ref heap_policy.
- * @tparam RefcountPolicy A *reference counting policy*, for example,
- * @ref refcount_policy.
- * @tparam TransiencePolicy A *transience policy*, for example,
- * @ref no_transience_policy.
- * @tparam PreferFewerBiggerObjects Boolean flag indicating whether
- * the user should prefer to allocate memory in bigger chunks
- * --e.g. by putting various objects in the same memory
- * region-- or not.
- * @tparam UseTransientRValues Boolean flag indicating whether
- * immutable containers should try to modify contents in-place
- * when manipulating an r-value reference.
- */
-template <typename HeapPolicy,
- typename RefcountPolicy,
- typename LockPolicy,
- typename TransiencePolicy = get_transience_policy_t<RefcountPolicy>,
- bool PreferFewerBiggerObjects =
- get_prefer_fewer_bigger_objects_v<HeapPolicy>,
- bool UseTransientRValues =
- get_use_transient_rvalues_v<RefcountPolicy>>
-struct memory_policy
-{
- using heap = HeapPolicy;
- using refcount = RefcountPolicy;
- using transience = TransiencePolicy;
- using lock = LockPolicy;
-
- static constexpr bool prefer_fewer_bigger_objects =
- PreferFewerBiggerObjects;
-
- static constexpr bool use_transient_rvalues = UseTransientRValues;
-
- using transience_t = typename transience::template apply<heap>::type;
-};
-
-/*!
- * The default *heap policy* just uses the standard heap with a
- * @ref free_list_heap_policy. If `IMMER_NO_FREE_LIST` is defined to `1`
- * then it just uses the standard heap.
- */
-#if IMMER_NO_FREE_LIST
-using default_heap_policy = heap_policy<debug_size_heap<cpp_heap>>;
-#else
-#if IMMER_NO_THREAD_SAFETY
-using default_heap_policy = unsafe_free_list_heap_policy<cpp_heap>;
-#else
-using default_heap_policy = free_list_heap_policy<cpp_heap>;
-#endif
-#endif
-
-/*!
- * By default we use thread safe reference counting.
- */
-#if IMMER_NO_THREAD_SAFETY
-using default_refcount_policy = unsafe_refcount_policy;
-using default_lock_policy = no_lock_policy;
-#else
-using default_refcount_policy = refcount_policy;
-using default_lock_policy = spinlock_policy;
-#endif
-
-/*!
- * The default memory policy.
- */
-using default_memory_policy = memory_policy<default_heap_policy,
- default_refcount_policy,
- default_lock_policy>;
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/refcount/enable_intrusive_ptr.hpp b/src/third_party/immer/dist/immer/refcount/enable_intrusive_ptr.hpp
deleted file mode 100644
index 1185a219fd9..00000000000
--- a/src/third_party/immer/dist/immer/refcount/enable_intrusive_ptr.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/refcount/no_refcount_policy.hpp>
-
-namespace immer {
-
-template <typename Deriv, typename RefcountPolicy>
-class enable_intrusive_ptr
-{
- mutable RefcountPolicy refcount_data_;
-
-public:
- enable_intrusive_ptr()
- : refcount_data_{disowned{}}
- {}
-
- friend void intrusive_ptr_add_ref(const Deriv* x)
- {
- x->refcount_data_.inc();
- }
-
- friend void intrusive_ptr_release(const Deriv* x)
- {
- if (x->refcount_data_.dec())
- delete x;
- }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/refcount/no_refcount_policy.hpp b/src/third_party/immer/dist/immer/refcount/no_refcount_policy.hpp
deleted file mode 100644
index 5706858b127..00000000000
--- a/src/third_party/immer/dist/immer/refcount/no_refcount_policy.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-namespace immer {
-
-struct disowned
-{};
-
-/*!
- * Disables reference counting, to be used with an alternative garbage
- * collection strategy like a `gc_heap`.
- */
-struct no_refcount_policy
-{
- no_refcount_policy(){};
- no_refcount_policy(disowned) {}
-
- void inc() {}
- bool dec() { return false; }
- bool unique() { return false; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/refcount/refcount_policy.hpp b/src/third_party/immer/dist/immer/refcount/refcount_policy.hpp
deleted file mode 100644
index 52b516e8593..00000000000
--- a/src/third_party/immer/dist/immer/refcount/refcount_policy.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/refcount/no_refcount_policy.hpp>
-
-#include <atomic>
-#include <cassert>
-#include <utility>
-
-namespace immer {
-
-/*!
- * A reference counting policy implemented using an *atomic* `int`
- * count. It is **thread-safe**.
- */
-struct refcount_policy
-{
- mutable std::atomic<int> refcount;
-
- refcount_policy()
- : refcount{1} {};
- refcount_policy(disowned)
- : refcount{0}
- {}
-
- void inc() { refcount.fetch_add(1, std::memory_order_relaxed); }
-
- bool dec() { return 1 == refcount.fetch_sub(1, std::memory_order_acq_rel); }
-
- bool unique() { return refcount == 1; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/refcount/unsafe_refcount_policy.hpp b/src/third_party/immer/dist/immer/refcount/unsafe_refcount_policy.hpp
deleted file mode 100644
index df65019b42a..00000000000
--- a/src/third_party/immer/dist/immer/refcount/unsafe_refcount_policy.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/refcount/no_refcount_policy.hpp>
-
-#include <atomic>
-#include <utility>
-
-namespace immer {
-
-/*!
- * A reference counting policy implemented using a raw `int` count.
- * It is **not thread-safe**.
- */
-struct unsafe_refcount_policy
-{
- mutable int refcount;
-
- unsafe_refcount_policy()
- : refcount{1} {};
- unsafe_refcount_policy(disowned)
- : refcount{0}
- {}
-
- void inc() { ++refcount; }
- bool dec() { return --refcount == 0; }
- bool unique() { return refcount == 1; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/set.hpp b/src/third_party/immer/dist/immer/set.hpp
deleted file mode 100644
index df4192f5104..00000000000
--- a/src/third_party/immer/dist/immer/set.hpp
+++ /dev/null
@@ -1,295 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/detail/hamts/champ_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <functional>
-
-namespace immer {
-
-template <typename T,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class set_transient;
-
-/*!
- * Immutable set representing an unordered bag of values.
- *
- * @tparam T The type of the values to be stored in the container.
- * @tparam Hash The type of a function object capable of hashing
- * values of type `T`.
- * @tparam Equal The type of a function object capable of comparing
- * values of type `T`.
- * @tparam MemoryPolicy Memory management policy. See @ref
- * memory_policy.
- *
- * @rst
- *
- * This container provides a good trade-off between cache locality,
- * membership checks, update performance and structural sharing. It
- * does so by storing the data in contiguous chunks of :math:`2^{B}`
- * elements. When storing big objects, the size of these contiguous
- * chunks can become too big, damaging performance. If this is
- * measured to be problematic for a specific use-case, it can be
- * solved by using a `immer::box` to wrap the type `T`.
- *
- * **Example**
- * .. literalinclude:: ../example/set/intro.cpp
- * :language: c++
- * :start-after: intro/start
- * :end-before: intro/end
- *
- * @endrst
- *
- */
-template <typename T,
- typename Hash = std::hash<T>,
- typename Equal = std::equal_to<T>,
- typename MemoryPolicy = default_memory_policy,
- detail::hamts::bits_t B = default_bits>
-class set
-{
- using impl_t = detail::hamts::champ<T, Hash, Equal, MemoryPolicy, B>;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
- struct project_value_ptr
- {
- const T* operator()(const T& v) const noexcept { return &v; }
- };
-
-public:
- using value_type = T;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const T&;
- using const_reference = const T&;
-
- using iterator =
- detail::hamts::champ_iterator<T, Hash, Equal, MemoryPolicy, B>;
- using const_iterator = iterator;
-
- using transient_type = set_transient<T, Hash, Equal, MemoryPolicy, B>;
-
- using memory_policy_type = MemoryPolicy;
-
- /*!
- * Default constructor. It creates a set of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- set() = default;
-
- /*!
- * Constructs a set containing the elements in `values`.
- */
- set(std::initializer_list<value_type> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a set containing the elements in the range
- * defined by the input iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- set(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when `value` is contained in the set or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename K,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const K& value) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(value);
- }
-
- /*!
- * Returns `1` when `value` is contained in the set or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const T& value) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(value);
- }
-
- /*!
- * Returns a pointer to the value if `value` is contained in the
- * set, or nullptr otherwise.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T* find(const T& value) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(value);
- }
-
- /*!
- * Returns a pointer to the value if `value` is contained in the
- * set, or nullptr otherwise.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename K,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const K& value) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(value);
- }
-
- /*!
- * Returns whether the sets are equal.
- */
- IMMER_NODISCARD bool operator==(const set& other) const
- {
- return impl_.equals(other.impl_);
- }
- IMMER_NODISCARD bool operator!=(const set& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns a set containing `value`. If the `value` is already in
- * the set, it returns the same set. It may allocate memory and
- * its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD set insert(T value) const&
- {
- return impl_.add(std::move(value));
- }
- IMMER_NODISCARD decltype(auto) insert(T value) &&
- {
- return insert_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns a set without `value`. If the `value` is not in the
- * set it returns the same set. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD set erase(const T& value) const&
- {
- return impl_.sub(value);
- }
- IMMER_NODISCARD decltype(auto) erase(const T& value) &&
- {
- return erase_move(move_t{}, value);
- }
-
- /*!
- * Returns an @a transient form of this container, a
- * `immer::set_transient`.
- */
- IMMER_NODISCARD transient_type transient() const&
- {
- return transient_type{impl_};
- }
- IMMER_NODISCARD transient_type transient() &&
- {
- return transient_type{std::move(impl_)};
- }
-
- /*!
- * Returns a value that can be used as identity for the container. If two
- * values have the same identity, they are guaranteed to be equal and to
- * contain the same objects. However, two equal containers are not
- * guaranteed to have the same identity.
- */
- void* identity() const { return impl_.root; }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-private:
- friend transient_type;
-
- set&& insert_move(std::true_type, value_type value)
- {
- impl_.add_mut({}, std::move(value));
- return std::move(*this);
- }
- set insert_move(std::false_type, value_type value)
- {
- return impl_.add(std::move(value));
- }
-
- set&& erase_move(std::true_type, const value_type& value)
- {
- impl_.sub_mut({}, value);
- return std::move(*this);
- }
- set erase_move(std::false_type, const value_type& value)
- {
- return impl_.sub(value);
- }
-
- set(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/set_transient.hpp b/src/third_party/immer/dist/immer/set_transient.hpp
deleted file mode 100644
index e07668e2923..00000000000
--- a/src/third_party/immer/dist/immer/set_transient.hpp
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/memory_policy.hpp>
-
-#include <functional>
-
-namespace immer {
-
-/*!
- * Mutable version of `immer::set`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename T,
- typename Hash = std::hash<T>,
- typename Equal = std::equal_to<T>,
- typename MemoryPolicy = default_memory_policy,
- detail::hamts::bits_t B = default_bits>
-class set_transient : MemoryPolicy::transience_t::owner
-{
- using base_t = typename MemoryPolicy::transience_t::owner;
- using owner_t = base_t;
-
-public:
- using persistent_type = set<T, Hash, Equal, MemoryPolicy, B>;
-
- using value_type = T;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const T&;
- using const_reference = const T&;
-
- using iterator = typename persistent_type::iterator;
- using const_iterator = iterator;
-
- /*!
- * Default constructor. It creates a set of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- set_transient() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when `value` is contained in the set or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename K,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const K& value) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(value);
- }
-
- /*!
- * Returns `1` when `value` is contained in the set or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const T& value) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(value);
- }
-
- /*!
- * Returns a pointer to the value if `value` is contained in the
- * set, or nullptr otherwise.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T* find(const T& value) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(value);
- }
-
- /*!
- * Returns a pointer to the value if `value` is contained in the
- * set, or nullptr otherwise.
- * It does not allocate memory and its complexity is *effectively*
- * @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename K,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const K& value) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(value);
- }
-
- /*!
- * Inserts `value` into the set, and does nothing if the value is already
- * there It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- void insert(T value) { impl_.add_mut(*this, std::move(value)); }
-
- /*!
- * Removes the `value` from the set, doing nothing if the value is not in
- * the set. It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- void erase(const T& value) { impl_.sub_mut(*this, value); }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::set`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return impl_;
- }
- IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
-
-private:
- friend persistent_type;
- using impl_t = typename persistent_type::impl_t;
-
- set_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-
-public:
- // Semi-private
- const impl_t& impl() const { return impl_; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/table.hpp b/src/third_party/immer/dist/immer/table.hpp
deleted file mode 100644
index 0e977c6a23b..00000000000
--- a/src/third_party/immer/dist/immer/table.hpp
+++ /dev/null
@@ -1,547 +0,0 @@
-#pragma once
-
-#include <immer/config.hpp>
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/detail/hamts/champ_iterator.hpp>
-#include <immer/memory_policy.hpp>
-#include <type_traits>
-
-namespace immer {
-
-template <typename T,
- typename KeyFn,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class table_transient;
-
-/*!
- * Function template to get the key in `immer::table_key_fn`.
- * It assumes the key is `id` class member.
- */
-template <typename T>
-auto get_table_key(T const& x) -> decltype(x.id)
-{
- return x.id;
-}
-
-/*!
- * Function template to set the key in `immer::table_key_fn`.
- * It assumes the key is `id` class member.
- */
-template <typename T, typename K>
-auto set_table_key(T x, K&& k) -> T
-{
- x.id = std::forward<K>(k);
- return x;
-}
-
-/*!
- * Default value for `KeyFn` in `immer::table`.
- * It assumes the key is `id` class member.
- */
-struct table_key_fn
-{
- template <typename T>
- decltype(auto) operator()(T&& x) const
- {
- return get_table_key(std::forward<T>(x));
- }
-
- template <typename T, typename K>
- auto operator()(T&& x, K&& k) const
- {
- return set_table_key(std::forward<T>(x), std::forward<K>(k));
- }
-};
-
-template <typename KeyFn, typename T>
-using table_key_t = std::decay_t<decltype(KeyFn{}(std::declval<T>()))>;
-
-/*!
- * Immutable unordered set of values of type `T`. Values are indexed via
- * `operator()(const T&)` from `KeyFn` template parameter.
- * By default, key is `&T::id`.
- *
- * @tparam T The type of the values to be stored in the container.
- * @tparam KeyFn Type which implements `operator()(const T&)`
- * @tparam Hash The type of a function object capable of hashing
- * values of type `T`.
- * @tparam Equal The type of a function object capable of comparing
- * values of type `T`.
- * @tparam MemoryPolicy Memory management policy. See @ref
- * memory_policy.
- *
- * @rst
- *
- * This container is based on the `immer::map` underlying data structure.
- *
- * This container provides a good trade-off between cache locality,
- * search, update performance and structural sharing. It does so by
- * storing the data in contiguous chunks of :math:`2^{B}` elements.
- * When storing big objects, the size of these contiguous chunks can
- * become too big, damaging performance. If this is measured to be
- * problematic for a specific use-case, it can be solved by using a
- * `immer::box` to wrap the type `T`.
- *
- * **Example**
- * .. literalinclude:: ../example/table/intro.cpp
- * :language: c++
- * :start-after: intro/start
- * :end-before: intro/end
- *
- * @endrst
- *
- */
-template <typename T,
- typename KeyFn = table_key_fn,
- typename Hash = std::hash<table_key_t<KeyFn, T>>,
- typename Equal = std::equal_to<table_key_t<KeyFn, T>>,
- typename MemoryPolicy = default_memory_policy,
- detail::hamts::bits_t B = default_bits>
-class table
-{
- using K = table_key_t<KeyFn, T>;
- using value_t = T;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
- struct project_value
- {
- const T& operator()(const value_t& v) const noexcept { return v; }
- T&& operator()(value_t&& v) const noexcept { return std::move(v); }
- };
-
- struct project_value_ptr
- {
- const T* operator()(const value_t& v) const noexcept
- {
- return std::addressof(v);
- }
- };
-
- struct combine_value
- {
- template <typename Kf, typename Tf>
- auto operator()(Kf&& k, Tf&& v) const
- {
- return KeyFn{}(std::forward<Tf>(v), std::forward<Kf>(k));
- }
- };
-
- struct default_value
- {
- const T& operator()() const
- {
- static T v{};
- return v;
- }
- };
-
- struct error_value
- {
- const T& operator()() const
- {
- IMMER_THROW(std::out_of_range{"key not found"});
- }
- };
-
- struct hash_key
- {
- std::size_t operator()(const value_t& v) const
- {
- return Hash{}(KeyFn{}(v));
- }
-
- template <typename Key>
- std::size_t operator()(const Key& v) const
- {
- return Hash{}(v);
- }
- };
-
- struct equal_key
- {
- bool operator()(const value_t& a, const value_t& b) const
- {
- auto ke = KeyFn{};
- return Equal{}(ke(a), ke(b));
- }
-
- template <typename Key>
- bool operator()(const value_t& a, const Key& b) const
- {
- return Equal{}(KeyFn{}(a), b);
- }
- };
-
- struct equal_value
- {
- bool operator()(const value_t& a, const value_t& b) const
- {
- return a == b;
- }
- };
-
- using impl_t =
- detail::hamts::champ<value_t, hash_key, equal_key, MemoryPolicy, B>;
-
-public:
- using key_type = K;
- using mapped_type = T;
- using value_type = T;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const value_type&;
- using const_reference = const value_type&;
-
- using iterator = detail::hamts::
- champ_iterator<value_t, hash_key, equal_key, MemoryPolicy, B>;
- using const_iterator = iterator;
-
- using transient_type =
- table_transient<T, KeyFn, Hash, Equal, MemoryPolicy, B>;
-
- using memory_policy_type = MemoryPolicy;
-
- /*!
- * Constructs a table containing the elements in `values`.
- */
- table(std::initializer_list<value_type> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a table containing the elements in the range
- * defined by the input iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- table(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Default constructor. It creates a table of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- table() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when the key `k` is contained in the table or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const Key& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns `1` when the key `k` is contained in the table or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const K& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T& operator[](const Key& k) const
- {
- return impl_.template get<project_value, default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T& operator[](const K& k) const
- {
- return impl_.template get<project_value, default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- const T& at(const Key& k) const
- {
- return impl_.template get<project_value, error_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- const T& at(const K& k) const
- {
- return impl_.template get<project_value, error_value>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`.
- * If there is no entry with such a key in the table,
- * a `nullptr` is returned. It does not allocate memory and
- * its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T* find(const K& k) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`.
- * If there is no entry with such a key in the table,
- * a `nullptr` is returned. It does not allocate memory and
- * its complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const Key& k) const
- {
- return impl_.template get<project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- IMMER_NODISCARD bool operator==(const table& other) const
- {
- return impl_.template equals<equal_value>(other.impl_);
- }
-
- IMMER_NODISCARD bool operator!=(const table& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns a table containing the `value`.
- * If there is an entry with its key is already,
- * it replaces this entry by `value`.
- * It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- IMMER_NODISCARD table insert(value_type value) const&
- {
- return impl_.add(std::move(value));
- }
-
- /*!
- * Returns a table containing the `value`.
- * If there is an entry with its key is already,
- * it replaces this entry by `value`.
- * It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- IMMER_NODISCARD decltype(auto) insert(value_type value) &&
- {
- return insert_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns `this->insert(fn((*this)[k]))`. In particular, `fn` maps
- * `T` to `T`. The key `k` will be replaced inside the value returned by
- * `fn`. It may allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- template <typename Fn>
- IMMER_NODISCARD table update(key_type k, Fn&& fn) const&
- {
- return impl_
- .template update<project_value, default_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
- template <typename Fn>
- IMMER_NODISCARD decltype(auto) update(key_type k, Fn&& fn) &&
- {
- return update_move(move_t{}, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Returns `this.count(k) ? this->insert(fn((*this)[k])) : *this`. In
- * particular, `fn` maps `T` to `T`. The key `k` will be replaced inside the
- * value returned by `fn`. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- IMMER_NODISCARD table update_if_exists(key_type k, Fn&& fn) const&
- {
- return impl_.template update_if_exists<project_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
- template <typename Fn>
- IMMER_NODISCARD decltype(auto) update_if_exists(key_type k, Fn&& fn) &&
- {
- return update_if_exists_move(
- move_t{}, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Returns a table without entries with given key `k`. If the key is not
- * present it returns `*this`. It may allocate
- * memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD table erase(const K& k) const& { return impl_.sub(k); }
-
- /*!
- * Returns a table without entries with given key `k`. If the key is not
- * present it returns `*this`. It may allocate
- * memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD decltype(auto) erase(const K& k) &&
- {
- return erase_move(move_t{}, k);
- }
-
- /*!
- * Returns a @a transient form of this container, an
- * `immer::table_transient`.
- */
- IMMER_NODISCARD transient_type transient() const&
- {
- return transient_type{impl_};
- }
-
- /*!
- * Returns a @a transient form of this container, an
- * `immer::table_transient`.
- */
- IMMER_NODISCARD transient_type transient() &&
- {
- return transient_type{std::move(impl_)};
- }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-private:
- friend transient_type;
-
- table&& insert_move(std::true_type, value_type value)
- {
- impl_.add_mut({}, std::move(value));
- return std::move(*this);
- }
- table insert_move(std::false_type, value_type value)
- {
- return impl_.add(std::move(value));
- }
-
- template <typename Fn>
- table&& update_move(std::true_type, key_type k, Fn&& fn)
- {
- impl_.template update_mut<project_value, default_value, combine_value>(
- {}, std::move(k), std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- table update_move(std::false_type, key_type k, Fn&& fn)
- {
- return impl_
- .template update<project_value, default_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
-
- template <typename Fn>
- table&& update_if_exists_move(std::true_type, key_type k, Fn&& fn)
- {
- impl_.template update_if_exists_mut<project_value, combine_value>(
- {}, std::move(k), std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- table update_if_exists_move(std::false_type, key_type k, Fn&& fn)
- {
- return impl_.template update_if_exists<project_value, combine_value>(
- std::move(k), std::forward<Fn>(fn));
- }
-
- table&& erase_move(std::true_type, const key_type& value)
- {
- impl_.sub_mut({}, value);
- return std::move(*this);
- }
- table erase_move(std::false_type, const key_type& value)
- {
- return impl_.sub(value);
- }
-
- table(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/table_transient.hpp b/src/third_party/immer/dist/immer/table_transient.hpp
deleted file mode 100644
index 30b0a8c689d..00000000000
--- a/src/third_party/immer/dist/immer/table_transient.hpp
+++ /dev/null
@@ -1,281 +0,0 @@
-#pragma once
-
-#include <immer/detail/hamts/champ.hpp>
-#include <immer/memory_policy.hpp>
-#include <type_traits>
-
-namespace immer {
-
-template <typename T,
- typename KeyFn,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class table;
-
-/*!
- * Mutable version of `immer::table`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename T,
- typename KeyFn,
- typename Hash,
- typename Equal,
- typename MemoryPolicy,
- detail::hamts::bits_t B>
-class table_transient : MemoryPolicy::transience_t::owner
-{
- using K = std::decay_t<decltype(KeyFn{}(std::declval<T>()))>;
- using base_t = typename MemoryPolicy::transience_t::owner;
- using owner_t = base_t;
-
-public:
- using persistent_type = table<T, KeyFn, Hash, Equal, MemoryPolicy, B>;
- using key_type = K;
- using mapped_type = T;
- using value_type = T;
- using size_type = detail::hamts::size_t;
- using diference_type = std::ptrdiff_t;
- using hasher = Hash;
- using key_equal = Equal;
- using reference = const value_type&;
- using const_reference = const value_type&;
-
- using iterator = typename persistent_type::iterator;
- using const_iterator = iterator;
-
- /*!
- * Default constructor. It creates a table of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- table_transient() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns `1` when the key `k` is contained in the table or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD size_type count(const Key& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns `1` when the key `k` is contained in the table or `0`
- * otherwise. It won't allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type count(const K& k) const
- {
- return impl_.template get<detail::constantly<size_type, 1>,
- detail::constantly<size_type, 0>>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T& operator[](const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, it returns a
- * default constructed value. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T& operator[](const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::default_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- const T& at(const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::error_value>(k);
- }
-
- /*!
- * Returns a `const` reference to the values associated to the key
- * `k`. If there is no entry with such a key in the table, throws an
- * `std::out_of_range` error. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- const T& at(const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value,
- typename persistent_type::error_value>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`.
- * If there is no entry with such a key in the table,
- * a `nullptr` is returned. It does not allocate memory and
- * its complexity is *effectively* @f$ O(1) @f$.
- */
- IMMER_NODISCARD const T* find(const K& k) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Returns a pointer to the value associated with the key `k`.
- * If there is no entry with such a key in the table,
- * a `nullptr` is returned. It does not allocate memory and
- * its complexity is *effectively* @f$ O(1) @f$.
- *
- * This overload participates in overload resolution only if
- * `Hash::is_transparent` is valid and denotes a type.
- */
- template <typename Key,
- typename U = Hash,
- typename = typename U::is_transparent>
- IMMER_NODISCARD const T* find(const Key& k) const
- {
- return impl_.template get<typename persistent_type::project_value_ptr,
- detail::constantly<const T*, nullptr>>(k);
- }
-
- /*!
- * Inserts `value` to the table.
- * If there is an entry with its key is already,
- * it replaces this entry by `value`.
- * It may allocate memory and its complexity is *effectively* @f$
- * O(1) @f$.
- */
- void insert(value_type value) { impl_.add_mut(*this, std::move(value)); }
-
- /*!
- * Returns `this->insert(fn((*this)[k]))`. In particular, `fn` maps `T` to
- * `T`. The key `k` will be set into the value returned bu `fn`. It may
- * allocate memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- void update(key_type k, Fn&& fn)
- {
- impl_.template update_mut<typename persistent_type::project_value,
- typename persistent_type::default_value,
- typename persistent_type::combine_value>(
- *this, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Returns `this->insert(fn((*this)[k]))` when `this->count(k) > 0`. In
- * particular, `fn` maps `T` to `T`. The key `k` will be replaced into the
- * value returned by `fn`. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- template <typename Fn>
- void update_if_exists(key_type k, Fn&& fn)
- {
- impl_.template update_if_exists_mut<
- typename persistent_type::project_value,
- typename persistent_type::combine_value>(
- *this, std::move(k), std::forward<Fn>(fn));
- }
-
- /*!
- * Removes table entry by given key `k` if there is any. It may allocate
- * memory and its complexity is *effectively* @f$ O(1) @f$.
- */
- void erase(const K& k) { impl_.sub_mut(*this, k); }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::table`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return impl_;
- }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::table`.
- */
- IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
-
-private:
- friend persistent_type;
- using impl_t = typename persistent_type::impl_t;
-
- table_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = impl_t::empty();
-
-public:
- // Semi-private
- const impl_t& impl() const { return impl_; }
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/transience/gc_transience_policy.hpp b/src/third_party/immer/dist/immer/transience/gc_transience_policy.hpp
deleted file mode 100644
index a569ed8b423..00000000000
--- a/src/third_party/immer/dist/immer/transience/gc_transience_policy.hpp
+++ /dev/null
@@ -1,113 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/heap/tags.hpp>
-
-#include <atomic>
-#include <memory>
-#include <utility>
-
-namespace immer {
-
-/*!
- * Provides transience ownership tracking when a *tracing garbage
- * collector* is used instead of reference counting.
- *
- * @rst
- *
- * .. warning:: Using this policy without an allocation scheme that
- * includes automatic tracing garbage collection may cause memory
- * leaks.
- *
- * @endrst
- */
-struct gc_transience_policy
-{
- template <typename HeapPolicy>
- struct apply
- {
- struct type
- {
- using heap_ = typename HeapPolicy::type;
-
- struct edit
- {
- void* v;
- edit(void* v_)
- : v{v_}
- {}
- edit() = delete;
- bool operator==(edit x) const { return v == x.v; }
- bool operator!=(edit x) const { return v != x.v; }
- };
-
- struct owner
- {
- void* make_token_()
- {
- return heap_::allocate(1, norefs_tag{});
- };
-
- mutable std::atomic<void*> token_;
-
- operator edit() { return {token_}; }
-
- owner()
- : token_{make_token_()}
- {}
- owner(const owner& o)
- : token_{make_token_()}
- {
- o.token_ = make_token_();
- }
- owner(owner&& o) noexcept
- : token_{o.token_.load()}
- {}
- owner& operator=(const owner& o)
- {
- o.token_ = make_token_();
- token_ = make_token_();
- return *this;
- }
- owner& operator=(owner&& o) noexcept
- {
- token_ = o.token_.load();
- return *this;
- }
- };
-
- struct ownee
- {
- edit token_{nullptr};
-
- ownee& operator=(edit e)
- {
- assert(e != noone);
- // This would be a nice safety plug but it sadly
- // does not hold during transient concatenation.
- // assert(token_ == e || token_ == edit{nullptr});
- token_ = e;
- return *this;
- }
-
- bool can_mutate(edit t) const { return token_ == t; }
- bool owned() const { return token_ != edit{nullptr}; }
- };
-
- static owner noone;
- };
- };
-};
-
-template <typename HP>
-typename gc_transience_policy::apply<HP>::type::owner
- gc_transience_policy::apply<HP>::type::noone = {};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/transience/no_transience_policy.hpp b/src/third_party/immer/dist/immer/transience/no_transience_policy.hpp
deleted file mode 100644
index 2f87df7a39b..00000000000
--- a/src/third_party/immer/dist/immer/transience/no_transience_policy.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-namespace immer {
-
-/*!
- * Disables any special *transience* tracking. To be used when
- * *reference counting* is available instead.
- */
-struct no_transience_policy
-{
- template <typename>
- struct apply
- {
- struct type
- {
- struct edit
- {};
-
- struct owner
- {
- operator edit() const { return {}; }
- };
-
- struct ownee
- {
- ownee& operator=(edit) { return *this; };
- bool can_mutate(edit) const { return false; }
- bool owned() const { return false; }
- };
-
- static owner noone;
- };
- };
-};
-
-template <typename HP>
-typename no_transience_policy::apply<HP>::type::owner
- no_transience_policy::apply<HP>::type::noone = {};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/vector.hpp b/src/third_party/immer/dist/immer/vector.hpp
deleted file mode 100644
index 8c8ab05d694..00000000000
--- a/src/third_party/immer/dist/immer/vector.hpp
+++ /dev/null
@@ -1,423 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/rbts/rbtree.hpp>
-#include <immer/detail/rbts/rbtree_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-#if IMMER_DEBUG_PRINT
-#include <immer/flex_vector.hpp>
-#endif
-
-namespace immer {
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class flex_vector;
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class vector_transient;
-
-/*!
- * Immutable sequential container supporting both random access and
- * structural sharing.
- *
- * @tparam T The type of the values to be stored in the container.
- * @tparam MemoryPolicy Memory management policy. See @ref
- * memory_policy.
- *
- * @rst
- *
- * This container provides a good trade-off between cache locality,
- * random access, update performance and structural sharing. It does
- * so by storing the data in contiguous chunks of :math:`2^{BL}`
- * elements. By default, when ``sizeof(T) == sizeof(void*)`` then
- * :math:`B=BL=5`, such that data would be stored in contiguous
- * chunks of :math:`32` elements.
- *
- * You may learn more about the meaning and implications of ``B`` and
- * ``BL`` parameters in the :doc:`implementation` section.
- *
- * .. note:: In several methods we say that their complexity is
- * *effectively* :math:`O(...)`. Do not confuse this with the word
- * *amortized*, which has a very different meaning. In this
- * context, *effective* means that while the
- * mathematically rigurous
- * complexity might be higher, for all practical matters the
- * provided complexity is more useful to think about the actual
- * cost of the operation.
- *
- * **Example**
- * .. literalinclude:: ../example/vector/intro.cpp
- * :language: c++
- * :start-after: intro/start
- * :end-before: intro/end
- *
- * @endrst
- */
-template <typename T,
- typename MemoryPolicy = default_memory_policy,
- detail::rbts::bits_t B = default_bits,
- detail::rbts::bits_t BL =
- detail::rbts::derive_bits_leaf<T, MemoryPolicy, B>>
-class vector
-{
- using impl_t = detail::rbts::rbtree<T, MemoryPolicy, B, BL>;
- using flex_t = flex_vector<T, MemoryPolicy, B, BL>;
-
- using move_t =
- std::integral_constant<bool, MemoryPolicy::use_transient_rvalues>;
-
-public:
- static constexpr auto bits = B;
- static constexpr auto bits_leaf = BL;
- using memory_policy = MemoryPolicy;
-
- using value_type = T;
- using reference = const T&;
- using size_type = detail::rbts::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = detail::rbts::rbtree_iterator<T, MemoryPolicy, B, BL>;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using transient_type = vector_transient<T, MemoryPolicy, B, BL>;
-
- /*!
- * Returns the maximum theoretical size supported by the internal structure
- * given the current B, BL.
- */
- constexpr static size_type max_size() { return impl_t::max_size(); }
-
- /*!
- * Default constructor. It creates a vector of `size() == 0`. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- vector() = default;
-
- /*!
- * Constructs a vector containing the elements in `values`.
- */
- vector(std::initializer_list<T> values)
- : impl_{impl_t::from_initializer_list(values)}
- {}
-
- /*!
- * Constructs a vector containing the elements in the range
- * defined by the input iterator `first` and range sentinel `last`.
- */
- template <typename Iter,
- typename Sent,
- std::enable_if_t<detail::compatible_sentinel_v<Iter, Sent>,
- bool> = true>
- vector(Iter first, Sent last)
- : impl_{impl_t::from_range(first, last)}
- {}
-
- /*!
- * Constructs a vector containing the element `val` repeated `n`
- * times.
- */
- vector(size_type n, T v = {})
- : impl_{impl_t::from_fill(n, v)}
- {}
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Access the last element.
- */
- IMMER_NODISCARD const T& back() const { return impl_.back(); }
-
- /*!
- * Access the first element.
- */
- IMMER_NODISCARD const T& front() const { return impl_.front(); }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ 0 index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- IMMER_NODISCARD reference operator[](size_type index) const
- {
- return impl_.get(index);
- }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Returns whether the vectors are equal.
- */
- IMMER_NODISCARD bool operator==(const vector& other) const
- {
- return impl_.equals(other.impl_);
- }
- IMMER_NODISCARD bool operator!=(const vector& other) const
- {
- return !(*this == other);
- }
-
- /*!
- * Returns a vector with `value` inserted at the end. It may
- * allocate memory and its complexity is *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/vector/vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: push-back/start
- * :end-before: push-back/end
- *
- * @endrst
- */
- IMMER_NODISCARD vector push_back(value_type value) const&
- {
- return impl_.push_back(std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) push_back(value_type value) &&
- {
- return push_back_move(move_t{}, std::move(value));
- }
-
- /*!
- * Returns a vector containing value `value` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/vector/vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: set/start
- * :end-before: set/end
- *
- * @endrst
- */
- IMMER_NODISCARD vector set(size_type index, value_type value) const&
- {
- return impl_.assoc(index, std::move(value));
- }
-
- IMMER_NODISCARD decltype(auto) set(size_type index, value_type value) &&
- {
- return set_move(move_t{}, index, std::move(value));
- }
-
- /*!
- * Returns a vector containing the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `0 >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/vector/vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: update/start
- * :end-before: update/end
- *
- * @endrst
- */
- template <typename FnT>
- IMMER_NODISCARD vector update(size_type index, FnT&& fn) const&
- {
- return impl_.update(index, std::forward<FnT>(fn));
- }
-
- template <typename FnT>
- IMMER_NODISCARD decltype(auto) update(size_type index, FnT&& fn) &&
- {
- return update_move(move_t{}, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Returns a vector containing only the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- *
- * @rst
- *
- * **Example**
- * .. literalinclude:: ../example/vector/vector.cpp
- * :language: c++
- * :dedent: 8
- * :start-after: take/start
- * :end-before: take/end
- *
- * @endrst
- */
- IMMER_NODISCARD vector take(size_type elems) const&
- {
- return impl_.take(elems);
- }
-
- IMMER_NODISCARD decltype(auto) take(size_type elems) &&
- {
- return take_move(move_t{}, elems);
- }
-
- /*!
- * Returns an @a transient form of this container, an
- * `immer::vector_transient`.
- */
- IMMER_NODISCARD transient_type transient() const& { return impl_; }
- IMMER_NODISCARD transient_type transient() && { return std::move(impl_); }
-
- /*!
- * Returns a value that can be used as identity for the container. If two
- * values have the same identity, they are guaranteed to be equal and to
- * contain the same objects. However, two equal containers are not
- * guaranteed to have the same identity.
- */
- std::pair<void*, void*> identity() const
- {
- return {impl_.root, impl_.tail};
- }
-
- // Semi-private
- const impl_t& impl() const { return impl_; }
-
-#if IMMER_DEBUG_PRINT
- void debug_print(std::ostream& out = std::cerr) const
- {
- flex_t{*this}.debug_print(out);
- }
-#endif
-
-private:
- friend flex_t;
- friend transient_type;
-
- vector(impl_t impl)
- : impl_(std::move(impl))
- {
-#if IMMER_DEBUG_PRINT
- // force the compiler to generate debug_print, so we can call
- // it from a debugger
- [](volatile auto) {}(&vector::debug_print);
-#endif
- }
-
- vector&& push_back_move(std::true_type, value_type value)
- {
- impl_.push_back_mut({}, std::move(value));
- return std::move(*this);
- }
- vector push_back_move(std::false_type, value_type value)
- {
- return impl_.push_back(std::move(value));
- }
-
- vector&& set_move(std::true_type, size_type index, value_type value)
- {
- impl_.assoc_mut({}, index, std::move(value));
- return std::move(*this);
- }
- vector set_move(std::false_type, size_type index, value_type value)
- {
- return impl_.assoc(index, std::move(value));
- }
-
- template <typename Fn>
- vector&& update_move(std::true_type, size_type index, Fn&& fn)
- {
- impl_.update_mut({}, index, std::forward<Fn>(fn));
- return std::move(*this);
- }
- template <typename Fn>
- vector update_move(std::false_type, size_type index, Fn&& fn)
- {
- return impl_.update(index, std::forward<Fn>(fn));
- }
-
- vector&& take_move(std::true_type, size_type elems)
- {
- impl_.take_mut({}, elems);
- return std::move(*this);
- }
- vector take_move(std::false_type, size_type elems)
- {
- return impl_.take(elems);
- }
-
- impl_t impl_ = {};
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/immer/vector_transient.hpp b/src/third_party/immer/dist/immer/vector_transient.hpp
deleted file mode 100644
index edf7668fe70..00000000000
--- a/src/third_party/immer/dist/immer/vector_transient.hpp
+++ /dev/null
@@ -1,200 +0,0 @@
-//
-// immer: immutable data structures for C++
-// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
-//
-// This software is distributed under the Boost Software License, Version 1.0.
-// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
-//
-
-#pragma once
-
-#include <immer/detail/rbts/rbtree.hpp>
-#include <immer/detail/rbts/rbtree_iterator.hpp>
-#include <immer/memory_policy.hpp>
-
-namespace immer {
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class vector;
-
-template <typename T,
- typename MemoryPolicy,
- detail::rbts::bits_t B,
- detail::rbts::bits_t BL>
-class flex_vector_transient;
-
-/*!
- * Mutable version of `immer::vector`.
- *
- * @rst
- *
- * Refer to :doc:`transients` to learn more about when and how to use
- * the mutable versions of immutable containers.
- *
- * @endrst
- */
-template <typename T,
- typename MemoryPolicy = default_memory_policy,
- detail::rbts::bits_t B = default_bits,
- detail::rbts::bits_t BL =
- detail::rbts::derive_bits_leaf<T, MemoryPolicy, B>>
-class vector_transient : MemoryPolicy::transience_t::owner
-{
- using impl_t = detail::rbts::rbtree<T, MemoryPolicy, B, BL>;
- using flex_t = flex_vector_transient<T, MemoryPolicy, B, BL>;
- using owner_t = typename MemoryPolicy::transience_t::owner;
-
-public:
- static constexpr auto bits = B;
- static constexpr auto bits_leaf = BL;
- using memory_policy = MemoryPolicy;
-
- using value_type = T;
- using reference = const T&;
- using size_type = detail::rbts::size_t;
- using difference_type = std::ptrdiff_t;
- using const_reference = const T&;
-
- using iterator = detail::rbts::rbtree_iterator<T, MemoryPolicy, B, BL>;
- using const_iterator = iterator;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using persistent_type = vector<T, MemoryPolicy, B, BL>;
-
- /*!
- * Default constructor. It creates a mutable vector of `size() ==
- * 0`. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- vector_transient() = default;
-
- /*!
- * Returns an iterator pointing at the first element of the
- * collection. It does not allocate memory and its complexity is
- * @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator begin() const { return {impl_}; }
-
- /*!
- * Returns an iterator pointing just after the last element of the
- * collection. It does not allocate and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD iterator end() const
- {
- return {impl_, typename iterator::end_t{}};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing at the first element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rbegin() const
- {
- return reverse_iterator{end()};
- }
-
- /*!
- * Returns an iterator that traverses the collection backwards,
- * pointing after the last element of the reversed collection. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD reverse_iterator rend() const
- {
- return reverse_iterator{begin()};
- }
-
- /*!
- * Returns the number of elements in the container. It does
- * not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD size_type size() const { return impl_.size; }
-
- /*!
- * Returns `true` if there are no elements in the container. It
- * does not allocate memory and its complexity is @f$ O(1) @f$.
- */
- IMMER_NODISCARD bool empty() const { return impl_.size == 0; }
-
- /*!
- * Returns a `const` reference to the element at position `index`.
- * It is undefined when @f$ 0 index \geq size() @f$. It does not
- * allocate memory and its complexity is *effectively* @f$ O(1)
- * @f$.
- */
- reference operator[](size_type index) const { return impl_.get(index); }
-
- /*!
- * Returns a `const` reference to the element at position
- * `index`. It throws an `std::out_of_range` exception when @f$
- * index \geq size() @f$. It does not allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- reference at(size_type index) const { return impl_.get_check(index); }
-
- /*!
- * Inserts `value` at the end. It may allocate memory and its
- * complexity is *effectively* @f$ O(1) @f$.
- */
- void push_back(value_type value)
- {
- impl_.push_back_mut(*this, std::move(value));
- }
-
- /*!
- * Sets to the value `value` at position `idx`.
- * Undefined for `index >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void set(size_type index, value_type value)
- {
- impl_.assoc_mut(*this, index, std::move(value));
- }
-
- /*!
- * Updates the vector to contain the result of the expression
- * `fn((*this)[idx])` at position `idx`.
- * Undefined for `0 >= size()`.
- * It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- template <typename FnT>
- void update(size_type index, FnT&& fn)
- {
- impl_.update_mut(*this, index, std::forward<FnT>(fn));
- }
-
- /*!
- * Resizes the vector to only contain the first `min(elems, size())`
- * elements. It may allocate memory and its complexity is
- * *effectively* @f$ O(1) @f$.
- */
- void take(size_type elems) { impl_.take_mut(*this, elems); }
-
- /*!
- * Returns an @a immutable form of this container, an
- * `immer::vector`.
- */
- IMMER_NODISCARD persistent_type persistent() &
- {
- this->owner_t::operator=(owner_t{});
- return impl_;
- }
- IMMER_NODISCARD persistent_type persistent() && { return std::move(impl_); }
-
-private:
- friend flex_t;
- friend persistent_type;
-
- vector_transient(impl_t impl)
- : impl_(std::move(impl))
- {}
-
- impl_t impl_ = {};
-};
-
-} // namespace immer
diff --git a/src/third_party/immer/dist/tools/gdb_pretty_printers/__init__.py b/src/third_party/immer/dist/tools/gdb_pretty_printers/__init__.py
deleted file mode 100644
index 1bb8bf6d7fd..00000000000
--- a/src/third_party/immer/dist/tools/gdb_pretty_printers/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-# empty
diff --git a/src/third_party/immer/dist/tools/gdb_pretty_printers/autoload.py b/src/third_party/immer/dist/tools/gdb_pretty_printers/autoload.py
deleted file mode 100644
index 727a777772e..00000000000
--- a/src/third_party/immer/dist/tools/gdb_pretty_printers/autoload.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import gdb.printing
-import os
-
-path = os.path.dirname(__file__)
-if not path in sys.path:
- sys.path.append(path)
-from printers import immer_lookup_function
-
-gdb.printing.register_pretty_printer(gdb.current_objfile(), immer_lookup_function)
-
-print("immer gdb pretty-printers loaded") \ No newline at end of file
diff --git a/src/third_party/immer/dist/tools/gdb_pretty_printers/printers.py b/src/third_party/immer/dist/tools/gdb_pretty_printers/printers.py
deleted file mode 100644
index c33e7efdf67..00000000000
--- a/src/third_party/immer/dist/tools/gdb_pretty_printers/printers.py
+++ /dev/null
@@ -1,485 +0,0 @@
-# Sourced from https://gist.github.com/dwightguth/283afe96b60b3793f3c02036701457f8
-# with light modifications.
-
-import gdb.printing
-import decimal
-import traceback
-import re
-
-MAX = 1 << 64 - 1
-
-
-class ArrayIter:
- def __init__(self, val):
- self.val_ptr = val.type.template_argument(0).pointer()
- self.v = val['impl_']
- self.size = self.v['size']
- self.i = 0
-
- def __iter__(self):
- return self
-
- def __next__(self):
- if self.i == self.size:
- raise StopIteration
- ptr = self.v['ptr']
- data = ptr.dereference()['impl']['d']['buffer'].address.reinterpret_cast(self.val_ptr)
- result = ('[%d]' % self.i, data[self.i])
- self.i += 1
- return result
-
-
-class Relaxed:
- def __init__(self, node, shift, relaxed, it):
- self.node = node
- self.shift = shift
- self.relaxed = relaxed
- self.it = it
- self.B = self.node.type.target().template_argument(2)
- self.BL = self.node.type.target().template_argument(3)
-
- def index(self, idx):
- offset = idx >> self.shift
- while self.relaxed.dereference()['d']['sizes'][offset] <= idx:
- offset += 1
- return offset
-
- def towards(self, idx):
- offset = self.index(idx)
- left_size = self.relaxed.dereference()['d']['sizes'][offset - 1] if offset else 0
- child = self.it.inner(self.node)[offset]
- is_leaf = self.shift == self.BL
- next_size = self.relaxed.dereference()['d']['sizes'][offset] - left_size
- next_idx = idx - left_size
- if is_leaf:
- return self.it.visit_leaf(LeafSub(child, next_size), next_idx)
- else:
- return self.it.visit_maybe_relaxed_sub(child, self.shift - self.B, next_size, next_idx)
-
-
-class LeafSub:
- def __init__(self, node, count):
- self.node = node
- self.count_ = count
- self.BL = self.node.type.target().template_argument(3)
- self.MASK = (1 << self.BL) - 1
-
- def index(self, idx):
- return idx & self.MASK
-
- def count(self):
- return self.count_
-
-
-class FullLeaf:
- def __init__(self, node):
- self.node = node
- self.BL = self.node.type.target().template_argument(3)
- self.BRANCHES = 1 << self.BL
- self.MASK = self.BRANCHES - 1
-
- def index(self, idx):
- return idx & self.MASK
-
- def count(self):
- return self.BRANCHES
-
-
-class Leaf:
- def __init__(self, node, size):
- self.node = node
- self.size = size
- self.BL = self.node.type.target().template_argument(3)
- self.MASK = (1 << self.BL) - 1
-
- def index(self, idx):
- return idx & self.MASK
-
- def count(self):
- return self.index(self.size - 1) + 1
-
-
-class RegularSub:
- def __init__(self, node, shift, size, it):
- self.node = node
- self.shift = shift
- self.size = size
- self.it = it
- self.B = self.node.type.target().template_argument(2)
- self.MASK = (1 << self.B) - 1
-
- def towards(self, idx):
- offset = self.index(idx)
- count = self.count()
- return self.it.towards_regular(self, idx, offset, count)
-
- def index(self, idx):
- return (idx >> self.shift) & self.MASK
-
- def count(self):
- return self.subindex(self.size - 1) + 1
-
- def subindex(self, idx):
- return idx >> self.shift
-
-
-class Regular:
- def __init__(self, node, shift, size, it):
- self.node = node
- self.shift = shift
- self.size = size
- self.it = it
- self.B = self.node.type.target().template_argument(2)
- self.MASK = (1 << self.B) - 1
-
- def index(self, idx):
- return (idx >> self.shift) & self.MASK
-
- def count(self):
- return self.index(self.size - 1) + 1
-
- def towards(self, idx):
- offset = self.index(idx)
- count = self.count()
- return self.it.towards_regular(self, idx, offset, count)
-
-
-class Full:
- def __init__(self, node, shift, it):
- self.node = node
- self.shift = shift
- self.it = it
- self.B = self.node.type.target().template_argument(2)
- self.BL = self.node.type.target().template_argument(3)
- self.MASK = (1 << self.B) - 1
-
- def index(self, idx):
- return (idx >> self.shift) & self.MASK
-
- def towards(self, idx):
- offset = self.index(idx)
- is_leaf = self.shift == self.BL
- child = self.it.inner(self.node)[offset]
- if is_leaf:
- return self.it.visit_leaf(FullLeaf(child), idx)
- else:
- return Full(child, self.shift - self.B, self.it).towards(idx)
-
-
-class ListIter:
- def __init__(self, val):
- self.v = val['impl_']
- self.size = self.v['size']
- self.i = 0
- self.curr = (None, MAX, MAX)
- self.node_ptr_ptr = self.v['root'].type.pointer()
- self.B = self.v['root'].type.target().template_argument(2)
- self.BL = self.v['root'].type.target().template_argument(3)
-
- def __iter__(self):
- return self
-
- def __next__(self):
- if self.i == self.size:
- raise StopIteration
- if self.i < self.curr[1] or self.i >= self.curr[2]:
- self.curr = self.region()
- result = ('[%d]' % self.i, self.curr[0][self.i - self.curr[1]].cast(
- gdb.lookup_type(self.v.type.template_argument(0).name)))
- self.i += 1
- return result
-
- def region(self):
- tail_off = self.tail_offset()
- if self.i >= tail_off:
- return (self.leaf(self.v['tail']), tail_off, self.size)
- else:
- subs = self.visit_maybe_relaxed_sub(self.v['root'], self.v['shift'], tail_off, self.i)
- first = self.i - subs[1]
- end = first + subs[2]
- return (subs[0], first, end)
-
- def tail_offset(self):
- r = self.relaxed(self.v['root'])
- if r:
- return r.dereference()['d']['sizes'][r.dereference()['d']['count'] - 1]
- elif self.size:
- return (self.size - 1) & ~self.leaf_mask()
- else:
- return 0
-
- def relaxed(self, node):
- return node.dereference()['impl']['d']['data']['inner']['relaxed']
-
- def leaf(self, node):
- return node.dereference()['impl']['d']['data']['leaf']['buffer'].address
-
- def inner(self, node):
- return node.dereference()['impl']['d']['data']['inner']['buffer'].address.reinterpret_cast(
- self.node_ptr_ptr)
-
- def visit_maybe_relaxed_sub(self, node, shift, size, idx):
- relaxed = self.relaxed(node)
- if relaxed:
- return Relaxed(node, shift, relaxed, self).towards(idx)
- else:
- return RegularSub(node, shift, size, self).towards(idx)
-
- def visit_leaf(self, pos, idx):
- return (self.leaf(pos.node), pos.index(idx), pos.count())
-
- # pos = node, idx = full, offset = shifted & masked, count = shifted
- def towards_regular(self, pos, idx, offset, count):
- is_leaf = pos.shift == self.BL
- child = self.inner(pos.node)[offset]
- is_full = offset + 1 != count
- if is_full:
- if is_leaf:
- return self.visit_leaf(FullLeaf(child), idx)
- else:
- return Full(child, pos.shift - self.B, self).towards(idx)
- elif is_leaf:
- return self.visit_leaf(Leaf(child, pos.size), idx)
- else:
- return Regular(child, pos.shift - self.B, pos.size, self).towards(idx)
-
- def leaf_mask(self):
- return (1 << self.BL) - 1
-
-
-def popcount(x):
- b = 0
- while x > 0:
- x &= x - 1
- b += 1
- return b
-
-
-class ChampIter:
- def __init__(self, val):
- self.depth = 0
- self.count = 0
- v = val['impl_']['root']
- self.node_ptr_ptr = v.type.pointer()
- m = self.datamap(v)
- if m:
- self.cur = self.values(v)
- self.end = self.values(v) + popcount(m)
- else:
- self.cur = None
- self.end = None
- self.path = [v.address]
- self.B = v.type.target().template_argument(4)
- self.MAX_DEPTH = ((8 * 8) + self.B - 1) / 8
- self.ensure_valid()
-
- def __iter__(self):
- return self
-
- def __next__(self):
- if self.cur == None:
- raise StopIteration
- result = self.cur.dereference()
- self.cur += 1
- self.count += 1
- self.ensure_valid()
- return result
-
- def ensure_valid(self):
- while self.cur == self.end:
- while self.step_down():
- if self.cur != self.end:
- return
- if not self.step_right():
- self.cur = None
- self.end = None
- return
-
- def step_down(self):
- if self.depth < self.MAX_DEPTH:
- parent = self.path[self.depth].dereference()
- if self.nodemap(parent):
- self.depth += 1
- self.path.append(self.children(parent))
- child = self.path[self.depth]
- if self.depth < self.MAX_DEPTH:
- m = self.datamap(child)
- if m:
- self.cur = self.values(child)
- self.end = self.cur + popcount(m)
- else:
- self.cur = self.collisions(child)
- self.end = self.cur = self.collision_count(child)
- return True
- return False
-
- def step_right(self):
- while self.depth > 0:
- parent = self.path[self.depth - 1].dereference()
- last = self.children(parent) + popcount(self.nodemap(parent))
- next_ = self.path[self.depth] + 1
- if next_ < last:
- self.path[self.depth] = next_
- child = self.path[self.depth].dereference()
- if self.depth < self.MAX_DEPTH:
- m = self.datamap(child)
- if m:
- self.cur = self.values(child)
- self.end = self.cur + popcount(m)
- else:
- self.cur = self.collisions(child)
- self.end = self.cur + self.collision_count(child)
- return True
- self.depth -= 1
- self.path.pop()
- return False
-
- def values(self, node):
- return node.dereference()['impl']['d']['data']['inner']['values'].dereference(
- )['d']['buffer'].address.cast(self.T_ptr)
-
- def children(self, node):
- return node.dereference()['impl']['d']['data']['inner']['buffer'].address.cast(
- self.node_ptr_ptr)
-
- def datamap(self, node):
- return node.dereference()['impl']['d']['data']['inner']['datamap']
-
- def nodemap(self, node):
- return node.dereference()['impl']['d']['data']['inner']['nodemap']
-
- def collision_count(self, node):
- return node.dereference()['impl']['d']['data']['collision']['count']
-
- def collisions(self, node):
- return node.dereference()['impl']['d']['data']['collision']['buffer'].address.cast(
- self.T_ptr)
-
-
-class MapIter(ChampIter):
- def __init__(self, val):
- self.T_ptr = gdb.lookup_type("std::pair<" + val.type.template_argument(0).name + ", " +
- val.type.template_argument(1).name + ">").pointer()
- ChampIter.__init__(self, val)
- self.pair = None
-
- def __next__(self):
- if self.pair:
- result = ('[%d]' % self.count, self.pair['second'])
- self.pair = None
- return result
- self.pair = super().__next__()
- return ('[%d]' % self.count, self.pair['first'])
-
-
-class SetIter(ChampIter):
- def __init__(self, val):
- self.T_ptr = gdb.lookup_type(val.type.template_argument(0).name).pointer()
- ChampIter.__init__(self, val)
-
- def __next__(self):
- return ('[%d]' % self.count, super().__next__())
-
-
-def num_elements(num):
- return '1 element' if num == 1 else '%d elements' % num
-
-
-class ArrayPrinter:
- "Prints an immer::array"
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- return 'immer::array with %s' % num_elements(self.val['impl_']['size'])
-
- def children(self):
- return ArrayIter(self.val)
-
- def display_hint(self):
- return 'array'
-
-
-class MapPrinter:
- "Print an immer::map"
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- return 'immer::map with %s' % num_elements(self.val['impl_']['size'])
-
- def children(self):
- return MapIter(self.val)
-
- def display_hint(self):
- return 'map'
-
-
-class SetPrinter:
- "Prints an immer::set"
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- return 'immer::set with %s' % num_elements(self.val['impl_']['size'])
-
- def children(self):
- return SetIter(self.val)
-
-
-class TablePrinter:
- "Prints an immer::table"
-
- def __init__(self, val):
- self.val = val
-
- def to_string(self):
- return 'immer::table with %s' % num_elements(self.val['impl_']['size'])
-
- def children(self):
- return SetIter(self.val)
-
-
-class ListPrinter:
- "Prints an immer::vector or immer::flex_vector"
-
- def __init__(self, val, typename):
- self.val = val
- self.typename = typename
-
- def to_string(self):
- return '%s of length %d' % (self.typename, int(self.val['impl_']['size']))
-
- def children(self):
- return ListIter(self.val)
-
- def display_hint(self):
- return 'array'
-
-
-def immer_lookup_function(val):
- compiled_rx = re.compile('^([a-zA-Z0-9_:]+)(<.*>)?$')
- typename = gdb.types.get_basic_type(val.type).tag
- if not typename:
- return None
- match = compiled_rx.match(typename)
- if not match:
- return None
-
- basename = match.group(1)
- if basename == "immer::array":
- return ArrayPrinter(val)
- elif basename == "immer::map":
- return MapPrinter(val)
- elif basename == "immer::set":
- return SetPrinter(val)
- elif basename == "immer::table":
- return TablePrinter(val)
- elif basename == "immer::vector":
- return ListPrinter(val, "immer::vector")
- elif basename == "immer::flex_vector":
- return ListPrinter(val, "immer::flex_vector")
- return None
diff --git a/src/third_party/immer/scripts/import.sh b/src/third_party/immer/scripts/import.sh
deleted file mode 100755
index f723bed2757..00000000000
--- a/src/third_party/immer/scripts/import.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-# This script downloads and imports immer.
-
-set -vxeuo pipefail
-
-IMMER_GIT_URL="https://github.com/mongodb-forks/immer.git"
-
-IMMER_GIT_REV=071f90b39267ae02dbd5b942d311e3a29b908331
-
-LIB_GIT_DIR=$(mktemp -d /tmp/import-immer.XXXXXX)
-trap "rm -rf $LIB_GIT_DIR" EXIT
-
-DEST_DIR=$(git rev-parse --show-toplevel)/src/third_party/immer
-if [[ -d $DEST_DIR/dist ]]; then
- echo "You must remove '$DEST_DIR/dist' before running $0" >&2
- exit 1
-fi
-
-git clone "$IMMER_GIT_URL" $LIB_GIT_DIR
-git -C $LIB_GIT_DIR checkout $IMMER_GIT_REV
-
-# Remove unnecessary stuff
-rm -rf $LIB_GIT_DIR/benchmark
-rm -rf $LIB_GIT_DIR/cmake
-rm -rf $LIB_GIT_DIR/doc
-rm -rf $LIB_GIT_DIR/example
-rm -rf $LIB_GIT_DIR/extra
-rm -rf $LIB_GIT_DIR/nix
-rm -rf $LIB_GIT_DIR/test
-rm -rf $LIB_GIT_DIR/tools/clojure
-rm -rf $LIB_GIT_DIR/tools/docker
-rm -rf $LIB_GIT_DIR/tools/include
-rm -rf $LIB_GIT_DIR/tools/scala
-rm -rf $LIB_GIT_DIR/tools/sinusoidal-sphinx-theme
-rm -rf $LIB_GIT_DIR/tools/reproduce-paper-results.bash
-rm -rf $LIB_GIT_DIR/tools/with-tee.bash
-rm -f $LIB_GIT_DIR/BUILD
-rm -f $LIB_GIT_DIR/CMakeLists.txt
-rm -f $LIB_GIT_DIR/Package.swift
-rm -f $LIB_GIT_DIR/WORKSPACE
-rm -f $LIB_GIT_DIR/codecov.yml
-rm -f $LIB_GIT_DIR/default.nix
-rm -f $LIB_GIT_DIR/setup.py
-rm -f $LIB_GIT_DIR/shell.nix
-rm -f $LIB_GIT_DIR/spm.cpp
-
-test -d $DEST_DIR/dist && rm -r $DEST_DIR/dist
-mkdir -p $DEST_DIR/dist
-mv $LIB_GIT_DIR/* $DEST_DIR/dist