diff --git a/Makefile.am b/Makefile.am
index 99fdca0183929..d160bda53afe1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -193,6 +193,7 @@ LCOV_FILTER_PATTERN = \
-p "/usr/lib/" \
-p "/usr/lib64/" \
-p "src/dashbls/" \
+ -p "src/immer/" \
-p "src/leveldb/" \
-p "src/crc32c/" \
-p "src/bench/" \
diff --git a/configure.ac b/configure.ac
index 396978c587f98..95f837b548d4a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1520,9 +1520,6 @@ dnl check if libgmp is present
AC_CHECK_HEADER([gmp.h],, AC_MSG_ERROR(libgmp headers missing))
AC_CHECK_LIB([gmp], [__gmpz_init],GMP_LIBS=-lgmp, AC_MSG_ERROR(libgmp missing))
-dnl check if immer headers-only library is present
-AC_CHECK_HEADER([immer/map.hpp],, AC_MSG_ERROR(immer map headers missing))
-
AC_MSG_CHECKING([whether to build dashd])
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])
AC_MSG_RESULT($build_bitcoind)
diff --git a/contrib/devtools/copyright_header.py b/contrib/devtools/copyright_header.py
index b5852ac2b0c7a..66727aaebcf31 100755
--- a/contrib/devtools/copyright_header.py
+++ b/contrib/devtools/copyright_header.py
@@ -34,6 +34,7 @@
# git subtrees
"src/crypto/ctaes/",
"src/dashbls/",
+ "src/immer/",
"src/leveldb/",
"src/secp256k1/",
"src/univalue/",
diff --git a/depends/packages/immer.mk b/depends/packages/immer.mk
deleted file mode 100644
index 444759939d575..0000000000000
--- a/depends/packages/immer.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-package=immer
-$(package)_version=v0.7.0
-$(package)_download_path=https://github.com/arximboldi/immer/archive
-$(package)_download_file=$($(package)_version).tar.gz
-$(package)_file_name=$(package)-$($(package)_download_file)
-$(package)_sha256_hash=cf67ab428aa3610eb0f72d0ea936c15cce3f91df26ee143ab783acd053507fe4
-$(package)_build_subdir=build_tmp
-$(package)_dependencies=cmake boost
-
-define $(package)_fetch_cmds
-$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash))
-endef
-
-define $(package)_set_vars
- $(package)_config_opts=-DCMAKE_INSTALL_INCLUDEDIR=$(host_prefix)/include
- $(package)_config_opts+=-DCMAKE_INSTALL_LIBDIR=$(host_prefix)/lib
- $(package)_config_opts_linux=-DCMAKE_SYSTEM_NAME=Linux
- $(package)_config_opts_darwin=-DCMAKE_SYSTEM_NAME=Darwin
- $(package)_config_opts_mingw32=-DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SHARED_LIBRARY_LINK_C_FLAGS=""
- ifneq ($(darwin_native_toolchain),)
- $(package)_config_opts_darwin+= -DCMAKE_AR="$(host_prefix)/native/bin/$($(package)_ar)"
- $(package)_config_opts_darwin+= -DCMAKE_RANLIB="$(host_prefix)/native/bin/$($(package)_ranlib)"
- endif
-endef
-
-define $(package)_config_cmds
- export CC="$($(package)_cc)" && \
- export CXX="$($(package)_cxx)" && \
- export CFLAGS="$($(package)_cflags) $($(package)_cppflags)" && \
- export CXXFLAGS="$($(package)_cxxflags) $($(package)_cppflags)" && \
- export LDFLAGS="$($(package)_ldflags)" && \
- $(host_prefix)/bin/cmake ../ $($(package)_config_opts)
-endef
-
-define $(package)_build_cmds
- $(MAKE) $($(package)_build_opts)
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk
index ace13db5d8740..543ff1dc5df2b 100644
--- a/depends/packages/packages.mk
+++ b/depends/packages/packages.mk
@@ -1,4 +1,4 @@
-packages:=boost libevent gmp backtrace cmake immer
+packages:=boost libevent gmp backtrace cmake
qt_linux_packages:=qt expat dbus libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon
diff --git a/src/Makefile.am b/src/Makefile.am
index 6304c3ed141d6..9952a2bfabf4d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,7 @@ endif #ENABLE_STACKTRACES
BITCOIN_INCLUDES=-I$(builddir) -I$(srcdir)/secp256k1/include -I$(srcdir)/$(UNIVALUE_INCLUDE_DIR_INT) $(BDB_CPPFLAGS) $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
BITCOIN_INCLUDES+=-I$(srcdir)/dashbls/include -I$(srcdir)/dashbls/depends/relic/include -I$(srcdir)/dashbls/depends/minialloc/include
+BITCOIN_INCLUDES+=-I$(srcdir)/immer
LIBBITCOIN_SERVER=libbitcoin_server.a
LIBBITCOIN_COMMON=libbitcoin_common.a
@@ -856,6 +857,7 @@ libdashconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
libdashconsensus_la_LIBADD = $(LIBDASHBLS) $(LIBSECP256K1) $(GMP_LIBS)
libdashconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj -I$(srcdir)/secp256k1/include -DBUILD_BITCOIN_INTERNAL
libdashconsensus_la_CPPFLAGS += -I$(srcdir)/dashbls/include -I$(srcdir)/dashbls/depends/relic/include -I$(srcdir)/dashbls/depends/minialloc/include
+libdashconsensus_la_CPPFLAGS += -I$(srcdir)/immer
libdashconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
endif
@@ -889,9 +891,13 @@ CLEANFILES += wallet/test/*.gcda wallet/test/*.gcno
CLEANFILES += zmq/*.gcda zmq/*.gcno
CLEANFILES += obj/build.h
+IMMER_DIST = immer/immer
LIBDASHBLS_DIST = dashbls
-EXTRA_DIST = $(CTAES_DIST) $(LIBDASHBLS_DIST)
+EXTRA_DIST = \
+ $(CTAES_DIST) \
+ $(IMMER_DIST) \
+ $(LIBDASHBLS_DIST)
config/bitcoin-config.h: config/stamp-h1
@$(MAKE) -C $(top_builddir) $(subdir)/$(@)
diff --git a/src/immer/.clang-format b/src/immer/.clang-format
new file mode 100644
index 0000000000000..97c11d2d758f5
--- /dev/null
+++ b/src/immer/.clang-format
@@ -0,0 +1,39 @@
+---
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: 'true'
+AlignEscapedNewlines: Right
+AlignTrailingComments: 'true'
+AllowShortFunctionsOnASingleLine: 'true'
+AllowShortBlocksOnASingleLine: 'true'
+AlwaysBreakTemplateDeclarations: 'true'
+AccessModifierOffset: -4
+BinPackArguments: 'false'
+BinPackParameters: 'false'
+BreakBeforeBraces: Mozilla
+BreakBeforeInheritanceComma: 'true'
+BreakBeforeTernaryOperators: 'true'
+BreakConstructorInitializers: BeforeComma
+BreakStringLiterals: 'true'
+ColumnLimit: '80'
+CompactNamespaces: 'false'
+ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
+FixNamespaceComments: 'true'
+ForEachMacros: ['IMMER_CATCH', 'IMMER_TRY']
+IndentCaseLabels: 'false'
+IndentWidth: '4'
+IndentWrappedFunctionNames: 'false'
+KeepEmptyLinesAtTheStartOfBlocks: 'false'
+Language: Cpp
+MaxEmptyLinesToKeep: '1'
+NamespaceIndentation: None
+PointerAlignment: Left
+ReflowComments: 'true'
+SortIncludes: 'true'
+SortUsingDeclarations: 'true'
+SpaceAfterCStyleCast: 'true'
+SpaceAfterTemplateKeyword: 'true'
+SpaceBeforeAssignmentOperators: 'true'
+SpaceBeforeParens: ControlStatements
+TabWidth: '4'
+UseTab: Never
+...
diff --git a/src/immer/.dir-locals.el b/src/immer/.dir-locals.el
new file mode 100644
index 0000000000000..8adc4f1d20320
--- /dev/null
+++ b/src/immer/.dir-locals.el
@@ -0,0 +1,7 @@
+((nil .
+ ((indent-tabs-mode . nil)
+ (show-trailing-whitespace . t)))
+ (c-mode .
+ ((mode . c++)))
+ (c++-mode .
+ ((eval add-hook 'before-save-hook #'clang-format-buffer nil t))))
diff --git a/src/immer/.github/FUNDING.yml b/src/immer/.github/FUNDING.yml
new file mode 100644
index 0000000000000..defc6ca1fa1de
--- /dev/null
+++ b/src/immer/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+github: arximboldi
+patreon: sinusoidal
+custom: ["paypal.me/sinusoidal", sinusoid.al]
diff --git a/src/immer/.github/workflows/test.yml b/src/immer/.github/workflows/test.yml
new file mode 100644
index 0000000000000..830892969a7b1
--- /dev/null
+++ b/src/immer/.github/workflows/test.yml
@@ -0,0 +1,123 @@
+name: test
+on: [push, pull_request]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0 # needed for fetchGit in default.nix
+ - uses: cachix/install-nix-action@v12
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+ install_url: "https://releases.nixos.org/nix/nix-2.3.16/install"
+ - uses: cachix/cachix-action@v8
+ with:
+ name: arximboldi
+ signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
+ - run: nix-build
+
+ docs:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: true
+ - uses: cachix/install-nix-action@v12
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+ install_url: "https://releases.nixos.org/nix/nix-2.3.16/install"
+ - uses: cachix/cachix-action@v8
+ with:
+ name: arximboldi
+ signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
+ - run: nix-shell --run "mkdir build"
+ - run: nix-shell --run "cd build && cmake .."
+ - run: nix-shell --run "cd build && make docs"
+ - uses: shimataro/ssh-key-action@v2
+ if: github.ref == 'refs/heads/master'
+ with:
+ key: ${{ secrets.SINUSOIDES_SSH_KEY }}
+ known_hosts: ${{ secrets.SINUSOIDES_KNOWN_HOSTS }}
+ - run: nix-shell --run "cd build && make upload-docs"
+ if: github.ref == 'refs/heads/master'
+
+ check:
+ strategy:
+ matrix:
+ type: [Debug, Release]
+ toolchain: [gnu-6, gnu-7, llvm-5, llvm-6]
+ std: [14]
+ opts: [[]]
+ include:
+ # coverage
+ - type: Debug
+ toolchain: gnu-9
+ std: 14
+ opts: ['coverage']
+ # std 17
+ - type: Debug
+ toolchain: gnu-8
+ std: 17
+ - type: Debug
+ toolchain: llvm-9
+ std: 17
+ opts: ['fuzzers']
+ # std 20
+ - type: Debug
+ toolchain: gnu-11
+ std: 20
+ - type: Debug
+ toolchain: llvm-13
+ std: 20
+ # sanitizers
+ - type: Debug
+ toolchain: llvm-8
+ std: 14
+ opts: ['sanitizer']
+ # benchmarks
+ - type: Release
+ toolchain: gnu-9
+ std: 14
+ opts: ['benchmark']
+ - type: Release
+ toolchain: llvm-10
+ std: 14
+ opts: ['benchmark']
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: cachix/install-nix-action@v12
+ with:
+ nix_path: nixpkgs=channel:nixos-unstable
+ install_url: "https://releases.nixos.org/nix/nix-2.3.16/install"
+ - uses: cachix/cachix-action@v8
+ with:
+ name: arximboldi
+ signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
+ - run: nix-shell --argstr toolchain ${{ matrix.toolchain }} --run "mkdir build"
+ - name: configure CMake
+ run: |
+ nix-shell --argstr toolchain ${{ matrix.toolchain }} --run "
+ cd build && cmake .. \
+ -DCMAKE_BUILD_TYPE=${{ matrix.type }} \
+ -DCHECK_SLOW_TESTS=false \
+ -DCXX_STANDARD=${{ matrix.std }} \
+ -DCHECK_BENCHMARKS=${{ contains(matrix.opts, 'benchmark') }} \
+ -DENABLE_COVERAGE=${{ contains(matrix.opts, 'coverage') }} \
+ -DENABLE_ASAN=${{ contains(matrix.opts, 'sanitize') }} \
+ -DENABLE_LSAN=${{ contains(matrix.opts, 'sanitize') }} \
+ -DENABLE_UBSAN=${{ contains(matrix.opts, 'sanitize') }} \
+ -DCHECK_FUZZERS=${{ contains(matrix.opts, 'fuzzers') }} \
+ -DDISABLE_FREE_LIST=${{ contains(matrix.opts, 'sanitize') }}
+ "
+ - run: nix-shell --argstr toolchain ${{ matrix.toolchain }} --run "cd build && make check -j`nproc`"
+ - run: nix-shell --argstr toolchain ${{ matrix.toolchain }} --run "bash <(curl -s https://codecov.io/bash)"
+ if: ${{ contains(matrix.opts, 'coverage') }}
+ - uses: shimataro/ssh-key-action@v2
+ if: ${{ contains(matrix.opts, 'benchmark') }}
+ with:
+ key: ${{ secrets.SINUSOIDES_SSH_KEY }}
+ known_hosts: ${{ secrets.SINUSOIDES_KNOWN_HOSTS }}
+ - run: nix-shell --run "cd build && make upload-benchmark-reports"
+ if: ${{ contains(matrix.opts, 'benchmark') }}
diff --git a/src/immer/.gitignore b/src/immer/.gitignore
new file mode 100644
index 0000000000000..2074141ec2619
--- /dev/null
+++ b/src/immer/.gitignore
@@ -0,0 +1,24 @@
+bazel-*
+build/
+build-*/
+reports/
+doc/_build
+doc/_doxygen
+bazel-*
+
+tools/travis/ssh-key
+tools/clojure/target/
+tools/scala/target/
+tools/scala/project/target/
+
+extra/js/out
+extra/js/boost
+
+__pycache__
+
+.gdb_history
+
+.cache
+tools/clojure/.lein*
+
+*.pyc
diff --git a/src/immer/.gitmodules b/src/immer/.gitmodules
new file mode 100644
index 0000000000000..53d1686014fd0
--- /dev/null
+++ b/src/immer/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "extra/python/lib/pybind11"]
+ path = extra/python/lib/pybind11
+ url = https://github.com/pybind/pybind11.git
+[submodule "tools/sinusoidal-sphinx-theme"]
+ path = tools/sinusoidal-sphinx-theme
+ url = https://github.com/arximboldi/sinusoidal-sphinx-theme.git
diff --git a/src/immer/BUILD b/src/immer/BUILD
new file mode 100644
index 0000000000000..3d79830b60a38
--- /dev/null
+++ b/src/immer/BUILD
@@ -0,0 +1,11 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+ name = "immer",
+ include_prefix = "immer",
+ strip_include_prefix =
+ "immer",
+ hdrs = glob([
+ "immer/**/*.hpp",
+ ]),
+)
diff --git a/src/immer/CMakeLists.txt b/src/immer/CMakeLists.txt
new file mode 100644
index 0000000000000..2362ecb763379
--- /dev/null
+++ b/src/immer/CMakeLists.txt
@@ -0,0 +1,155 @@
+
+cmake_minimum_required(VERSION 3.5.1)
+cmake_policy(SET CMP0048 NEW) # enable project VERSION
+cmake_policy(SET CMP0056 NEW) # honor link flags in try_compile()
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+project(immer VERSION 0.7.0)
+
+if (NOT MSVC)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Wno-unused-parameter -Wno-extended-offsetof -Wno-c++17-extensions -Wno-c++1z-extensions -Wno-unknown-warning-option -Wno-type-limits")
+endif()
+set(CMAKE_EXPORT_COMPILE_COMMANDS on)
+set(CMAKE_CXX_EXTENSIONS off)
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments")
+endif()
+
+include(GNUInstallDirs)
+include(ImmerUtils)
+
+# Options
+# =======
+
+option(ENABLE_ASAN "compile with address sanitizer enabled")
+option(ENABLE_MSAN "compile with memory sanitizer enabled")
+option(ENABLE_LSAN "compile with leak sanitizer enabled")
+option(ENABLE_UBSAN "compile with undefined behavior sanitizer enabled")
+option(ENABLE_COVERAGE "compile with test coverage support")
+option(DISABLE_WERROR "enable --werror")
+option(DISABLE_FREE_LIST "disables the free list heap")
+option(DISABLE_THREAD_SAFETY "disables thread safety by default")
+option(CHECK_FUZZERS "Add fuzzers as part of make check")
+
+option(ENABLE_PYTHON "enable building python module" off)
+option(ENABLE_GUILE "enable building guile module" off)
+option(ENABLE_BOOST_COROUTINE "run benchmarks with boost coroutine" off)
+
+option(immer_BUILD_TESTS "Build tests" ON)
+option(immer_BUILD_EXAMPLES "Build examples" ON)
+option(immer_BUILD_DOCS "Build docs" ON)
+option(immer_BUILD_EXTRAS "Build extras" ON)
+
+set(CXX_STANDARD 14 CACHE STRING "c++ standard number")
+
+set(CMAKE_CXX_STANDARD ${CXX_STANDARD})
+set(CMAKE_CXX_STANDARD_REQUIRED on)
+
+if (ENABLE_ASAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
+endif()
+if (ENABLE_LSAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak")
+endif()
+if (ENABLE_UBSAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
+endif()
+if (ENABLE_MSAN)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=memory")
+endif()
+
+if (NOT MSVC AND NOT DISABLE_WERROR)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+endif()
+
+# Dependencies
+# ============
+
+if (ENABLE_BOOST_COROUTINE)
+ set(immer_boost_components coroutine)
+endif()
+
+find_package(Threads)
+find_package(BoehmGC)
+find_package(Boost 1.56 COMPONENTS ${immer_boost_components})
+
+find_program(CCACHE ccache)
+if (CCACHE)
+ message(STATUS "Using ccache: ${CCACHE}")
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE})
+ set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE})
+else()
+ message(STATUS "Could not find ccache")
+endif()
+
+if (NOT BOEHM_GC_FOUND)
+ set(BOEHM_GC_LIBRARIES "")
+endif()
+
+# Targets
+# =======
+
+# the library
+add_library(immer INTERFACE)
+target_include_directories(immer INTERFACE
+ $
+ $
+ $)
+install(TARGETS immer EXPORT ImmerConfig)
+install(EXPORT ImmerConfig DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Immer")
+install(DIRECTORY immer DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
+
+# development target to be used in tests, examples, benchmarks...
+immer_canonicalize_cmake_booleans(
+ DISABLE_FREE_LIST
+ DISABLE_THREAD_SAFETY
+ CHECK_SLOW_TESTS)
+add_library(immer-dev INTERFACE)
+target_include_directories(immer-dev SYSTEM INTERFACE
+ ${Boost_INCLUDE_DIR}
+ ${BOEHM_GC_INCLUDE_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/tools/include)
+target_link_libraries(immer-dev INTERFACE
+ immer
+ ${BOEHM_GC_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT})
+target_compile_definitions(immer-dev INTERFACE
+ -DIMMER_CXX_STANDARD=${CXX_STANDARD}
+ -DIMMER_HAS_LIBGC=1
+ -DIMMER_NO_FREE_LIST=${DISABLE_FREE_LIST}
+ -DIMMER_NO_THREAD_SAFETY=${DISABLE_THREAD_SAFETY}
+ -DIMMER_SLOW_TESTS=${CHECK_SLOW_TESTS}
+ -DFMT_HEADER_ONLY=1)
+if (ENABLE_COVERAGE)
+ target_compile_options(immer-dev INTERFACE "--coverage")
+ target_link_libraries(immer-dev INTERFACE "--coverage")
+endif()
+
+# Testing
+# =======
+
+if (immer_BUILD_TESTS)
+ enable_testing()
+
+ add_custom_target(check
+ COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Build and run all the tests and examples.")
+
+ add_subdirectory(test)
+ add_subdirectory(benchmark)
+endif()
+
+if (immer_BUILD_EXAMPLES)
+ add_subdirectory(example)
+endif()
+
+if (immer_BUILD_DOCS)
+ add_subdirectory(doc)
+endif()
+
+if (immer_BUILD_EXTRAS)
+ add_subdirectory(extra/fuzzer)
+ add_subdirectory(extra/python)
+ add_subdirectory(extra/guile)
+endif()
diff --git a/src/immer/LICENSE b/src/immer/LICENSE
new file mode 100644
index 0000000000000..36b7cd93cdfba
--- /dev/null
+++ b/src/immer/LICENSE
@@ -0,0 +1,23 @@
+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/immer/README.rst b/src/immer/README.rst
new file mode 100644
index 0000000000000..abf4dceae1467
--- /dev/null
+++ b/src/immer/README.rst
@@ -0,0 +1,224 @@
+.. 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
+
+
+
+.. 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
+
+
+
+
+
+ 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
+ int main()
+ {
+ const auto v0 = immer::vector{};
+ 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 `_ built with this
+ library. You may also wanna check `Lager, a Redux-like library
+ `_ for writting 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
+`_ and is also included
+in the ``LICENSE`` file of this software package.
diff --git a/src/immer/WORKSPACE b/src/immer/WORKSPACE
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/immer/benchmark/CMakeLists.txt b/src/immer/benchmark/CMakeLists.txt
new file mode 100644
index 0000000000000..c9fcc7e173957
--- /dev/null
+++ b/src/immer/benchmark/CMakeLists.txt
@@ -0,0 +1,127 @@
+
+# Config
+# ======
+
+option(CHECK_BENCHMARKS "Run benchmarks on check target" off)
+option(BENCHMARK_DISABLE_GC "Disable gc during a measurement")
+
+set(BENCHMARK_PARAM "N:1000" CACHE STRING "Benchmark parameters")
+set(BENCHMARK_SAMPLES "20" CACHE STRING "Benchmark samples")
+
+# Dependencies
+# ============
+
+find_package(RRB)
+
+if (NOT RRB_FOUND)
+ message(STATUS "Disabling benchmarks")
+ return()
+endif()
+
+# These are expected to be in the include path, the nix-shell
+# environment installs them:
+#
+# https://github.com/marcusz/steady
+# https://github.com/deepsea-inria/chunkedseq.git
+# https://github.com/rsms/immutable-cpp.git
+
+# Targets
+# =======
+
+add_custom_target(benchmarks
+ COMMENT "Build all benchmarks.")
+
+execute_process(
+ COMMAND git log -1 --format=%h
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE immer_git_commit_hash
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+execute_process(
+ COMMAND git status --porcelain
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE immer_git_status
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if (NOT immer_git_status STREQUAL "")
+ set(immer_git_commit_hash "${immer_git_commit_hash}+")
+endif()
+
+site_name(immer_hostname)
+
+get_filename_component(immer_compiler_name "${CMAKE_CXX_COMPILER}" NAME)
+
+set(immer_benchmark_report_base_dir "${CMAKE_SOURCE_DIR}/reports")
+set(immer_benchmark_report_dir "${immer_benchmark_report_base_dir}/report_\
+${immer_git_commit_hash}_\
+${immer_hostname}_\
+${immer_compiler_name}_\
+${BENCHMARK_PARAM}_\
+s${BENCHMARK_SAMPLES}")
+
+if(DISABLE_FREE_LIST)
+ set(immer_benchmark_report_dir "${immer_benchmark_report_dir}_nofl")
+endif()
+
+if(DISABLE_THREAD_SAFETY)
+ set(immer_benchmark_report_dir "${immer_benchmark_report_dir}_nots")
+endif()
+
+if(BENCHMARK_DISABLE_GC)
+ set(immer_benchmark_report_dir "${immer_benchmark_report_dir}_nogc")
+endif()
+
+if(CHECK_BENCHMARKS)
+ add_dependencies(check benchmarks)
+endif()
+
+add_custom_target(benchmark-report-dir
+ COMMAND ${CMAKE_COMMAND}
+ -E make_directory ${immer_benchmark_report_dir})
+
+file(GLOB_RECURSE immer_benchmarks "*.cpp")
+foreach(_file IN LISTS immer_benchmarks)
+ immer_target_name_for(_target _output "${_file}")
+ add_executable(${_target} EXCLUDE_FROM_ALL "${_file}")
+ set_target_properties(${_target} PROPERTIES OUTPUT_NAME ${_output})
+ add_dependencies(benchmarks ${_target})
+ add_dependencies(${_target} benchmark-report-dir)
+ target_compile_options(${_target} PUBLIC -Wno-unused-function)
+ target_compile_definitions(${_target} PUBLIC
+ NONIUS_RUNNER
+ IMMER_BENCHMARK_LIBRRB=1
+ IMMER_BENCHMARK_STEADY=1
+ IMMER_BENCHMARK_EXPERIMENTAL=0
+ IMMER_BENCHMARK_DISABLE_GC=${BENCHMARK_DISABLE_GC}
+ IMMER_BENCHMARK_BOOST_COROUTINE=${ENABLE_BOOST_COROUTINE})
+ target_link_libraries(${_target} PUBLIC
+ immer-dev
+ ${RRB_LIBRARIES})
+ target_include_directories(${_target} SYSTEM PUBLIC
+ ${RRB_INCLUDE_DIR})
+ if(CHECK_BENCHMARKS)
+ add_test("benchmark/${_output}" "${CMAKE_SOURCE_DIR}/tools/with-tee.bash"
+ ${immer_benchmark_report_dir}/${_target}.out
+ "${CMAKE_CURRENT_BINARY_DIR}/${_output}" -v
+ -t ${_target}
+ -r html
+ -s ${BENCHMARK_SAMPLES}
+ -p ${BENCHMARK_PARAM}
+ -o ${immer_benchmark_report_dir}/${_target}.html)
+ endif()
+endforeach()
+
+set(immer_ssh_method
+ ssh -p 5488
+ -o StrictHostKeyChecking=no)
+
+add_custom_target(upload-benchmark-reports
+ COMMAND
+ rsync -av -e \"${immer_ssh_method}\"
+ ${immer_benchmark_report_base_dir}
+ raskolnikov@sinusoid.es:public/misc/immer/)
+
+add_custom_target(copy-benchmark-reports
+ COMMAND
+ rsync -av ${immer_benchmark_report_base_dir}
+ ~/public/misc/immer/)
diff --git a/src/immer/benchmark/config.hpp b/src/immer/benchmark/config.hpp
new file mode 100644
index 0000000000000..b0c0994a1f6ef
--- /dev/null
+++ b/src/immer/benchmark/config.hpp
@@ -0,0 +1,69 @@
+//
+// 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
+
+#include
+#include
+
+namespace {
+
+NONIUS_PARAM(N, std::size_t{1000})
+
+struct gc_disable
+{
+ gc_disable()
+ {
+#if IMMER_BENCHMARK_DISABLE_GC
+ GC_disable();
+#else
+ GC_gcollect();
+#endif
+ }
+ ~gc_disable()
+ {
+#if IMMER_BENCHMARK_DISABLE_GC
+ GC_enable();
+ GC_gcollect();
+#endif
+ }
+ gc_disable(const gc_disable&) = delete;
+ gc_disable(gc_disable&&) = delete;
+};
+
+template
+void measure(Meter& m, Fn&& fn)
+{
+ gc_disable guard;
+ return m.measure(std::forward(fn));
+}
+
+using def_memory = immer::default_memory_policy;
+using gc_memory = immer::memory_policy,
+ immer::no_refcount_policy,
+ immer::default_lock_policy>;
+using gcf_memory = immer::memory_policy,
+ immer::no_refcount_policy,
+ immer::default_lock_policy,
+ immer::gc_transience_policy,
+ false>;
+using basic_memory = immer::memory_policy,
+ immer::refcount_policy,
+ immer::default_lock_policy>;
+using safe_memory =
+ immer::memory_policy,
+ immer::refcount_policy,
+ immer::default_lock_policy>;
+using unsafe_memory =
+ immer::memory_policy,
+ immer::unsafe_refcount_policy,
+ immer::default_lock_policy>;
+
+} // anonymous namespace
diff --git a/src/immer/benchmark/extra/refcounting.cpp b/src/immer/benchmark/extra/refcounting.cpp
new file mode 100644
index 0000000000000..c7c5183e6264b
--- /dev/null
+++ b/src/immer/benchmark/extra/refcounting.cpp
@@ -0,0 +1,146 @@
+//
+// 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
+//
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+NONIUS_PARAM(N, std::size_t{1000})
+
+constexpr auto benchmark_size = 32u;
+
+struct object_t : immer::detail::ref_count_base
+{};
+
+auto make_data()
+{
+ auto objs = std::array, benchmark_size>();
+ std::generate(objs.begin(), objs.end(), [] {
+ return std::make_unique();
+ });
+ auto refs = std::array();
+ std::transform(objs.begin(), objs.end(), refs.begin(), [](auto& obj) {
+ return obj.get();
+ });
+ return make_pair(std::move(objs),
+ std::move(refs));
+}
+
+NONIUS_BENCHMARK("intrusive_ptr", [] (nonius::chronometer meter)
+{
+ auto arr = std::array, benchmark_size>{};
+ auto storage = std::vector<
+ nonius::storage_for<
+ std::array, benchmark_size>>> (
+ meter.runs());
+ std::generate(arr.begin(), arr.end(), [] {
+ return new object_t{};
+ });
+ meter.measure([&] (int i) {
+ storage[i].construct(arr);
+ });
+})
+
+NONIUS_BENCHMARK("generic", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ std::transform(refs.begin(), refs.end(), r, [] (auto& p) {
+ if (p) p->ref_count.fetch_add(1, std::memory_order_relaxed);
+ return p;
+ });
+ return r;
+ });
+})
+
+NONIUS_BENCHMARK("manual", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ for (auto& p : refs)
+ if (p) p->ref_count.fetch_add(1, std::memory_order_relaxed);
+ std::copy(refs.begin(), refs.end(), r);
+ return r;
+ });
+})
+
+NONIUS_BENCHMARK("manual - unroll", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ auto e = refs.end();
+ for (auto p = refs.begin(); p != e;) {
+ (*p++)->ref_count.fetch_add(1, std::memory_order_relaxed);
+ (*p++)->ref_count.fetch_add(1, std::memory_order_relaxed);
+ (*p++)->ref_count.fetch_add(1, std::memory_order_relaxed);
+ (*p++)->ref_count.fetch_add(1, std::memory_order_relaxed);
+ }
+ std::copy(refs.begin(), refs.end(), r);
+ return r;
+ });
+})
+
+NONIUS_BENCHMARK("manual - nocheck", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ for (auto& p : refs)
+ p->ref_count.fetch_add(1, std::memory_order_relaxed);
+ std::copy(refs.begin(), refs.end(), r);
+ return r;
+ });
+})
+
+NONIUS_BENCHMARK("manual - constant", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ for (auto i = 0u; i < benchmark_size; ++i)
+ refs[i]->ref_count.fetch_add(1, std::memory_order_relaxed);
+ std::copy(refs.begin(), refs.end(), r);
+ return r;
+ });
+})
+
+NONIUS_BENCHMARK("manual - memcopy", [] (nonius::chronometer meter)
+{
+ auto data = make_data();
+ auto& refs = data.second;
+ object_t* r[benchmark_size];
+
+ meter.measure([&] {
+ for (auto& p : refs)
+ if (p) p->ref_count.fetch_add(1, std::memory_order_relaxed);
+ std::memcpy(r, &refs[0], sizeof(object_t*) * benchmark_size);
+ return r;
+ });
+})
diff --git a/src/immer/benchmark/set/access.hpp b/src/immer/benchmark/set/access.hpp
new file mode 100644
index 0000000000000..8605c0ff453c7
--- /dev/null
+++ b/src/immer/benchmark/set/access.hpp
@@ -0,0 +1,175 @@
+//
+// 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 "benchmark/config.hpp"
+
+#include
+#include // Phil Nash
+#include
+#include
+#include
+
+namespace {
+
+template
+auto make_generator_ranged(std::size_t runs)
+{
+ assert(runs > 0);
+ auto engine = std::default_random_engine{13};
+ auto dist = std::uniform_int_distribution{0, (T)runs-1};
+ auto r = std::vector(runs);
+ std::generate_n(r.begin(), runs, std::bind(dist, engine));
+ return r;
+}
+
+template
+auto benchmark_access_std()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+ auto g2 = make_generator_ranged(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i)
+ c += v.count(g1[g2[i]]);
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_access_hamt()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+ auto g2 = make_generator_ranged(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i) {
+ auto& x = g1[g2[i]];
+ auto leaf = v.find(x).leaf();
+ c += !!(leaf && leaf->find(x));
+ }
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+
+template
+auto benchmark_access()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+ auto g2 = make_generator_ranged(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v = v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i)
+ c += v.count(g1[g2[i]]);
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_bad_access_std()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n*2);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i)
+ c += v.count(g1[n+i]);
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_bad_access_hamt()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n*2);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i) {
+ auto& x = g1[n+i];
+ auto leaf = v.find(x).leaf();
+ c += !!(leaf && leaf->find(x));
+ }
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+
+template
+auto benchmark_bad_access()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n*2);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v = v.insert(g1[i]);
+
+ measure(meter, [&] {
+ auto c = 0u;
+ for (auto i = 0u; i < n; ++i)
+ c += v.count(g1[n+i]);
+ volatile auto r = c;
+ return r;
+ });
+ };
+}
+
+} // namespace
diff --git a/src/immer/benchmark/set/access.ipp b/src/immer/benchmark/set/access.ipp
new file mode 100644
index 0000000000000..f026d9cfa736e
--- /dev/null
+++ b/src/immer/benchmark/set/access.ipp
@@ -0,0 +1,30 @@
+//
+// 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
+//
+
+#include "access.hpp"
+
+#ifndef GENERATOR_T
+#error "you must define a GENERATOR_T"
+#endif
+
+using generator__ = GENERATOR_T;
+using t__ = typename decltype(generator__{}(0))::value_type;
+
+NONIUS_BENCHMARK("std::set", benchmark_access_std>())
+NONIUS_BENCHMARK("std::unordered_set", benchmark_access_std>())
+NONIUS_BENCHMARK("boost::flat_set", benchmark_access_std>())
+NONIUS_BENCHMARK("hamt::hash_trie", benchmark_access_hamt>())
+NONIUS_BENCHMARK("immer::set/5B", benchmark_access,std::equal_to,def_memory,5>>())
+NONIUS_BENCHMARK("immer::set/4B", benchmark_access,std::equal_to,def_memory,4>>())
+
+NONIUS_BENCHMARK("bad/std::set", benchmark_bad_access_std>())
+NONIUS_BENCHMARK("bad/std::unordered_set", benchmark_bad_access_std>())
+NONIUS_BENCHMARK("bad/boost::flat_set", benchmark_bad_access_std>())
+NONIUS_BENCHMARK("bad/hamt::hash_trie", benchmark_bad_access_hamt>())
+NONIUS_BENCHMARK("bad/immer::set/5B", benchmark_bad_access,std::equal_to,def_memory,5>>())
+NONIUS_BENCHMARK("bad/immer::set/4B", benchmark_bad_access,std::equal_to,def_memory,4>>())
diff --git a/src/immer/benchmark/set/insert.hpp b/src/immer/benchmark/set/insert.hpp
new file mode 100644
index 0000000000000..be679b4de342b
--- /dev/null
+++ b/src/immer/benchmark/set/insert.hpp
@@ -0,0 +1,55 @@
+//
+// 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 "benchmark/config.hpp"
+
+#include
+#include // Phil Nash
+#include
+#include
+#include
+
+namespace {
+
+template
+auto benchmark_insert_mut_std()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g = Generator{}(n);
+
+ measure(meter, [&] {
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g[i]);
+ return v;
+ });
+ };
+}
+
+template
+auto benchmark_insert()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g = Generator{}(n);
+
+ measure(meter, [&] {
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v = v.insert(g[i]);
+ return v;
+ });
+ };
+}
+
+} // namespace
diff --git a/src/immer/benchmark/set/insert.ipp b/src/immer/benchmark/set/insert.ipp
new file mode 100644
index 0000000000000..6717ccd57ea73
--- /dev/null
+++ b/src/immer/benchmark/set/insert.ipp
@@ -0,0 +1,28 @@
+//
+// 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
+//
+
+#include "insert.hpp"
+
+#ifndef GENERATOR_T
+#error "you must define a GENERATOR_T"
+#endif
+
+using generator__ = GENERATOR_T;
+using t__ = typename decltype(generator__{}(0))::value_type;
+
+NONIUS_BENCHMARK("std::set", benchmark_insert_mut_std>())
+NONIUS_BENCHMARK("std::unordered_set", benchmark_insert_mut_std>())
+NONIUS_BENCHMARK("boost::flat_set", benchmark_insert_mut_std>())
+NONIUS_BENCHMARK("hamt::hash_trie", benchmark_insert_mut_std>())
+
+NONIUS_BENCHMARK("immer::set/5B", benchmark_insert,std::equal_to,def_memory,5>>())
+NONIUS_BENCHMARK("immer::set/4B", benchmark_insert,std::equal_to,def_memory,4>>())
+#ifndef DISABLE_GC_BENCHMARKS
+NONIUS_BENCHMARK("immer::set/GC", benchmark_insert,std::equal_to,gc_memory,5>>())
+#endif
+NONIUS_BENCHMARK("immer::set/UN", benchmark_insert,std::equal_to,unsafe_memory,5>>())
diff --git a/src/immer/benchmark/set/iter.hpp b/src/immer/benchmark/set/iter.hpp
new file mode 100644
index 0000000000000..91dd486443677
--- /dev/null
+++ b/src/immer/benchmark/set/iter.hpp
@@ -0,0 +1,111 @@
+//
+// 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 "benchmark/config.hpp"
+
+#include
+#include
+#include
+#include // Phil Nash
+#include
+#include
+#include
+#include
+
+namespace {
+
+template
+struct iter_step
+{
+ unsigned operator() (unsigned x, const T& y) const
+ {
+ return x + y;
+ }
+};
+
+template <>
+struct iter_step
+{
+ unsigned operator() (unsigned x, const std::string& y) const
+ {
+ return x + (unsigned) y.size();
+ }
+};
+
+template <>
+struct iter_step>
+{
+ unsigned operator() (unsigned x, const immer::box& y) const
+ {
+ return x + (unsigned) y->size();
+ }
+};
+
+template
+auto benchmark_access_std_iter()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v.insert(g1[i]);
+
+ using step_t = iter_step;
+ measure(meter, [&] {
+ volatile auto c = std::accumulate(v.begin(), v.end(), 0u, step_t{});
+ return c;
+ });
+ };
+}
+
+template
+auto benchmark_access_reduce()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v = v.insert(g1[i]);
+
+ using step_t = iter_step;
+ measure(meter, [&] {
+ volatile auto c = immer::accumulate(v, 0u, step_t{});
+ return c;
+ });
+ };
+}
+
+template
+auto benchmark_access_iter()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g1 = Generator{}(n);
+
+ auto v = Set{};
+ for (auto i = 0u; i < n; ++i)
+ v = v.insert(g1[i]);
+
+ using step_t = iter_step;
+ measure(meter, [&] {
+ volatile auto c = std::accumulate(v.begin(), v.end(), 0u, step_t{});
+ return c;
+ });
+ };
+}
+
+} // namespace
diff --git a/src/immer/benchmark/set/iter.ipp b/src/immer/benchmark/set/iter.ipp
new file mode 100644
index 0000000000000..f8c3cb9695cde
--- /dev/null
+++ b/src/immer/benchmark/set/iter.ipp
@@ -0,0 +1,25 @@
+//
+// 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
+//
+
+#include "iter.hpp"
+
+#ifndef GENERATOR_T
+#error "you must define a GENERATOR_T"
+#endif
+
+using generator__ = GENERATOR_T;
+using t__ = typename decltype(generator__{}(0))::value_type;
+
+NONIUS_BENCHMARK("iter/std::set", benchmark_access_std_iter>())
+NONIUS_BENCHMARK("iter/std::unordered_set", benchmark_access_std_iter>())
+NONIUS_BENCHMARK("iter/boost::flat_set", benchmark_access_std_iter>())
+NONIUS_BENCHMARK("iter/hamt::hash_trie", benchmark_access_std_iter>())
+NONIUS_BENCHMARK("iter/immer::set/5B", benchmark_access_iter,std::equal_to,def_memory,5>>())
+NONIUS_BENCHMARK("iter/immer::set/4B", benchmark_access_iter,std::equal_to,def_memory,4>>())
+NONIUS_BENCHMARK("reduce/immer::set/5B", benchmark_access_reduce,std::equal_to,def_memory,5>>())
+NONIUS_BENCHMARK("reduce/immer::set/4B", benchmark_access_reduce,std::equal_to,def_memory,4>>())
diff --git a/src/immer/benchmark/set/string-box/access.cpp b/src/immer/benchmark/set/string-box/access.cpp
new file mode 100644
index 0000000000000..c3deffbb0636e
--- /dev/null
+++ b/src/immer/benchmark/set/string-box/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../access.ipp"
diff --git a/src/immer/benchmark/set/string-box/generator.ipp b/src/immer/benchmark/set/string-box/generator.ipp
new file mode 100644
index 0000000000000..9adc82e0bdc0a
--- /dev/null
+++ b/src/immer/benchmark/set/string-box/generator.ipp
@@ -0,0 +1,46 @@
+//
+// 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
+//
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#define GENERATOR_T generate_unsigned
+
+namespace {
+
+struct GENERATOR_T
+{
+ static constexpr auto char_set = "_-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ static constexpr auto max_length = 64;
+ static constexpr auto min_length = 8;
+
+ auto operator() (std::size_t runs) const
+ {
+ assert(runs > 0);
+ auto engine = std::default_random_engine{42};
+ auto dist = std::uniform_int_distribution{};
+ auto gen = std::bind(dist, engine);
+ auto r = std::vector>(runs);
+ std::generate_n(r.begin(), runs, [&] {
+ auto len = gen() % (max_length - min_length) + min_length;
+ auto str = std::string(len, ' ');
+ std::generate_n(str.begin(), len, [&] {
+ return char_set[gen() % sizeof(char_set)];
+ });
+ return str;
+ });
+ return r;
+ }
+};
+
+} // namespace
diff --git a/src/immer/benchmark/set/string-box/insert.cpp b/src/immer/benchmark/set/string-box/insert.cpp
new file mode 100644
index 0000000000000..c5762498c23c1
--- /dev/null
+++ b/src/immer/benchmark/set/string-box/insert.cpp
@@ -0,0 +1,11 @@
+//
+// 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
+//
+
+#define DISABLE_GC_BENCHMARKS
+#include "generator.ipp"
+#include "../insert.ipp"
diff --git a/src/immer/benchmark/set/string-box/iter.cpp b/src/immer/benchmark/set/string-box/iter.cpp
new file mode 100644
index 0000000000000..83e57e7845d3f
--- /dev/null
+++ b/src/immer/benchmark/set/string-box/iter.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../iter.ipp"
diff --git a/src/immer/benchmark/set/string-long/access.cpp b/src/immer/benchmark/set/string-long/access.cpp
new file mode 100644
index 0000000000000..c3deffbb0636e
--- /dev/null
+++ b/src/immer/benchmark/set/string-long/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../access.ipp"
diff --git a/src/immer/benchmark/set/string-long/generator.ipp b/src/immer/benchmark/set/string-long/generator.ipp
new file mode 100644
index 0000000000000..386364cc96fe4
--- /dev/null
+++ b/src/immer/benchmark/set/string-long/generator.ipp
@@ -0,0 +1,44 @@
+//
+// 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
+//
+
+#include
+#include
+#include
+#include
+#include
+
+#define GENERATOR_T generate_unsigned
+
+namespace {
+
+struct GENERATOR_T
+{
+ static constexpr auto char_set = "_-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ static constexpr auto max_length = 256;
+ static constexpr auto min_length = 32;
+
+ auto operator() (std::size_t runs) const
+ {
+ assert(runs > 0);
+ auto engine = std::default_random_engine{42};
+ auto dist = std::uniform_int_distribution{};
+ auto gen = std::bind(dist, engine);
+ auto r = std::vector(runs);
+ std::generate_n(r.begin(), runs, [&] {
+ auto len = gen() % (max_length - min_length) + min_length;
+ auto str = std::string(len, ' ');
+ std::generate_n(str.begin(), len, [&] {
+ return char_set[gen() % sizeof(char_set)];
+ });
+ return str;
+ });
+ return r;
+ }
+};
+
+} // namespace
diff --git a/src/immer/benchmark/set/string-long/insert.cpp b/src/immer/benchmark/set/string-long/insert.cpp
new file mode 100644
index 0000000000000..c5762498c23c1
--- /dev/null
+++ b/src/immer/benchmark/set/string-long/insert.cpp
@@ -0,0 +1,11 @@
+//
+// 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
+//
+
+#define DISABLE_GC_BENCHMARKS
+#include "generator.ipp"
+#include "../insert.ipp"
diff --git a/src/immer/benchmark/set/string-long/iter.cpp b/src/immer/benchmark/set/string-long/iter.cpp
new file mode 100644
index 0000000000000..83e57e7845d3f
--- /dev/null
+++ b/src/immer/benchmark/set/string-long/iter.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../iter.ipp"
diff --git a/src/immer/benchmark/set/string-short/access.cpp b/src/immer/benchmark/set/string-short/access.cpp
new file mode 100644
index 0000000000000..c3deffbb0636e
--- /dev/null
+++ b/src/immer/benchmark/set/string-short/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../access.ipp"
diff --git a/src/immer/benchmark/set/string-short/generator.ipp b/src/immer/benchmark/set/string-short/generator.ipp
new file mode 100644
index 0000000000000..bd40d2d639a8e
--- /dev/null
+++ b/src/immer/benchmark/set/string-short/generator.ipp
@@ -0,0 +1,44 @@
+//
+// 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
+//
+
+#include
+#include
+#include
+#include
+#include
+
+#define GENERATOR_T generate_unsigned
+
+namespace {
+
+struct GENERATOR_T
+{
+ static constexpr auto char_set = "_-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ static constexpr auto max_length = 15;
+ static constexpr auto min_length = 4;
+
+ auto operator() (std::size_t runs) const
+ {
+ assert(runs > 0);
+ auto engine = std::default_random_engine{42};
+ auto dist = std::uniform_int_distribution{};
+ auto gen = std::bind(dist, engine);
+ auto r = std::vector(runs);
+ std::generate_n(r.begin(), runs, [&] {
+ auto len = gen() % (max_length - min_length) + min_length;
+ auto str = std::string(len, ' ');
+ std::generate_n(str.begin(), len, [&] {
+ return char_set[gen() % sizeof(char_set)];
+ });
+ return str;
+ });
+ return r;
+ }
+};
+
+} // namespace
diff --git a/src/immer/benchmark/set/string-short/insert.cpp b/src/immer/benchmark/set/string-short/insert.cpp
new file mode 100644
index 0000000000000..26dfbce292042
--- /dev/null
+++ b/src/immer/benchmark/set/string-short/insert.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../insert.ipp"
diff --git a/src/immer/benchmark/set/string-short/iter.cpp b/src/immer/benchmark/set/string-short/iter.cpp
new file mode 100644
index 0000000000000..83e57e7845d3f
--- /dev/null
+++ b/src/immer/benchmark/set/string-short/iter.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../iter.ipp"
diff --git a/src/immer/benchmark/set/unsigned/access.cpp b/src/immer/benchmark/set/unsigned/access.cpp
new file mode 100644
index 0000000000000..c3deffbb0636e
--- /dev/null
+++ b/src/immer/benchmark/set/unsigned/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../access.ipp"
diff --git a/src/immer/benchmark/set/unsigned/generator.ipp b/src/immer/benchmark/set/unsigned/generator.ipp
new file mode 100644
index 0000000000000..2a2a2a0fb6278
--- /dev/null
+++ b/src/immer/benchmark/set/unsigned/generator.ipp
@@ -0,0 +1,32 @@
+//
+// 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
+//
+
+#include
+#include
+#include
+#include
+#include
+
+#define GENERATOR_T generate_unsigned
+
+namespace {
+
+struct GENERATOR_T
+{
+ auto operator() (std::size_t runs) const
+ {
+ assert(runs > 0);
+ auto engine = std::default_random_engine{42};
+ auto dist = std::uniform_int_distribution{};
+ auto r = std::vector(runs);
+ std::generate_n(r.begin(), runs, std::bind(dist, engine));
+ return r;
+ }
+};
+
+} // namespace
diff --git a/src/immer/benchmark/set/unsigned/insert.cpp b/src/immer/benchmark/set/unsigned/insert.cpp
new file mode 100644
index 0000000000000..26dfbce292042
--- /dev/null
+++ b/src/immer/benchmark/set/unsigned/insert.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../insert.ipp"
diff --git a/src/immer/benchmark/set/unsigned/iter.cpp b/src/immer/benchmark/set/unsigned/iter.cpp
new file mode 100644
index 0000000000000..83e57e7845d3f
--- /dev/null
+++ b/src/immer/benchmark/set/unsigned/iter.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#include "generator.ipp"
+#include "../iter.ipp"
diff --git a/src/immer/benchmark/vector/access.hpp b/src/immer/benchmark/vector/access.hpp
new file mode 100644
index 0000000000000..4dff7a667f332
--- /dev/null
+++ b/src/immer/benchmark/vector/access.hpp
@@ -0,0 +1,261 @@
+//
+// 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 "benchmark/vector/common.hpp"
+
+#include
+
+#if IMMER_BENCHMARK_BOOST_COROUTINE
+#include
+#endif
+
+namespace {
+
+template
+auto benchmark_access_reduce_chunkedseq()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v.push_back(i);
+ return [=] {
+ auto init = 0u;
+ v.for_each_segment([&] (auto first, auto last) {
+ init = std::accumulate(first, last, init);
+ });
+ return init;
+ };
+ };
+}
+
+template
+auto benchmark_access_iter_std()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v.push_back(i);
+ return [=] {
+ auto volatile x = std::accumulate(v.begin(), v.end(), 0u);
+ return x;
+ };
+ };
+}
+
+template
+auto benchmark_access_idx_std()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v.push_back(i);
+ return [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += v[i];
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+template
+auto benchmark_access_random_std()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+ auto v = Vektor{};
+ auto g = make_generator(n);
+ for (auto i = 0u; i < n; ++i)
+ v.push_back(i);
+ return [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += v[g[i]];
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+template
+auto benchmark_access_iter()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ return [=] {
+ auto volatile x = std::accumulate(v.begin(), v.end(), 0u);
+ return x;
+ };
+ };
+}
+
+#if IMMER_BENCHMARK_BOOST_COROUTINE
+template
+auto benchmark_access_coro()
+{
+ return [] (nonius::parameters params)
+ {
+ using coro_t = typename boost::coroutines2::coroutine;
+
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ return [=] {
+ auto c = coro_t::pull_type { [&](auto& sink) {
+ v.for_each_chunk([&](auto f, auto l) {
+ for (; f != l; ++f)
+ sink(*f);
+ });
+ }};
+ auto volatile x = std::accumulate(begin(c), end(c), 0u);
+ return x;
+ };
+ };
+}
+#endif
+
+template
+auto benchmark_access_idx()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ return [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += v[i];
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+template
+auto benchmark_access_reduce()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ return [=] {
+ auto volatile x = immer::accumulate(v, 0u);
+ return x;
+ };
+ };
+}
+
+template
+auto benchmark_access_reduce_range()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ return [=] {
+ auto volatile x = immer::accumulate(v.begin(), v.end(), 0u);
+ return x;
+ };
+ };
+}
+
+template
+auto benchmark_access_random()
+{
+ return [] (nonius::parameters params)
+ {
+ auto n = params.get();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+ auto g = make_generator(n);
+
+ return [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += v[g[i]];
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+template
+auto benchmark_access_librrb(Fn maker)
+{
+ return
+ [=] (nonius::parameters params) {
+ auto n = params.get();
+ auto v = maker(n);
+ return
+ [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += reinterpret_cast(rrb_nth(v, i));
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+template
+auto benchmark_access_random_librrb(Fn maker)
+{
+ return
+ [=] (nonius::parameters params) {
+ auto n = params.get();
+ auto v = maker(n);
+ auto g = make_generator(n);
+ return
+ [=] {
+ auto r = 0u;
+ for (auto i = 0u; i < n; ++i)
+ r += reinterpret_cast(rrb_nth(v, g[i]));
+ volatile auto rr = r;
+ return rr;
+ };
+ };
+}
+
+} // anonymous namespace
diff --git a/src/immer/benchmark/vector/assoc.hpp b/src/immer/benchmark/vector/assoc.hpp
new file mode 100644
index 0000000000000..5619d7ee6936d
--- /dev/null
+++ b/src/immer/benchmark/vector/assoc.hpp
@@ -0,0 +1,245 @@
+//
+// 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 "benchmark/vector/common.hpp"
+
+namespace {
+
+template
+auto benchmark_assoc_std()
+{
+ return
+ [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto v = Vektor(n, 0);
+ std::iota(v.begin(), v.end(), 0u);
+ auto all = std::vector(meter.runs(), v);
+ meter.measure([&] (int iter) {
+ auto& r = all[iter];
+ for (auto i = 0u; i < n; ++i)
+ r[i] = n - i;
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_random_std()
+{
+ return
+ [](nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ auto g = make_generator(n);
+ auto v = Vektor(n, 0);
+ std::iota(v.begin(), v.end(), 0u);
+ auto all = std::vector(meter.runs(), v);
+ meter.measure([&] (int iter) {
+ auto& r = all[iter];
+ for (auto i = 0u; i < n; ++i)
+ r[g[i]] = n - i;
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ if (n > get_limit{})
+ nonius::skip();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ measure(meter, [&] {
+ auto r = v;
+ for (auto i = 0u; i < n; ++i)
+ r = SetFn{}(r, i, n - i);
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_move()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ if (n > get_limit{})
+ nonius::skip();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ measure(meter, [&] {
+ auto r = v;
+ for (auto i = 0u; i < n; ++i)
+ r = std::move(r).set(i, n - i);
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_random()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ if (n > get_limit{})
+ nonius::skip();
+
+ auto g = make_generator(n);
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ measure(meter, [&] {
+ auto r = v;
+ for (auto i = 0u; i < n; ++i)
+ r = SetFn{}(r, g[i], i);
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_mut()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ if (n > get_limit{})
+ nonius::skip();
+
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ measure(meter, [&] {
+ auto r = v.transient();
+ for (auto i = 0u; i < n; ++i)
+ r.set(i, n - i);
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_mut_random()
+{
+ return [] (nonius::chronometer meter)
+ {
+ auto n = meter.param();
+ if (n > get_limit{})
+ nonius::skip();
+
+ auto g = make_generator(n);
+ auto v = Vektor{};
+ for (auto i = 0u; i < n; ++i)
+ v = PushFn{}(std::move(v), i);
+
+ measure(meter, [&] {
+ auto r = v.transient();
+ for (auto i = 0u; i < n; ++i)
+ r.set(g[i], i);
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_librrb(Fn maker)
+{
+ return
+ [=] (nonius::chronometer meter) {
+ auto n = meter.param();
+ auto v = maker(n);
+ measure(
+ meter, [&] {
+ auto r = v;
+ for (auto i = 0u; i < n; ++i)
+ r = rrb_update(r, i, reinterpret_cast(n - i));
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_random_librrb(Fn maker)
+{
+ return
+ [=] (nonius::chronometer meter) {
+ auto n = meter.param();
+ auto v = maker(n);
+ auto g = make_generator(n);
+ measure(
+ meter, [&] {
+ auto r = v;
+ for (auto i = 0u; i < n; ++i)
+ r = rrb_update(r, g[i], reinterpret_cast(i));
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_mut_librrb(Fn maker)
+{
+ return
+ [=] (nonius::chronometer meter) {
+ auto n = meter.param();
+ auto v = maker(n);
+ measure(
+ meter, [&] {
+ auto r = rrb_to_transient(v);
+ for (auto i = 0u; i < n; ++i)
+ r = transient_rrb_update(
+ r, i, reinterpret_cast(i));
+ return r;
+ });
+ };
+}
+
+template
+auto benchmark_assoc_mut_random_librrb(Fn maker)
+{
+ return
+ [=] (nonius::chronometer meter) {
+ auto n = meter.param();
+ auto v = maker(n);
+ auto g = make_generator(n);
+ measure(
+ meter, [&] {
+ auto r = rrb_to_transient(v);
+ for (auto i = 0u; i < n; ++i)
+ r = transient_rrb_update(
+ r, g[i], reinterpret_cast(i));
+ return r;
+ });
+ };
+}
+
+} // anonymous namespace
diff --git a/src/immer/benchmark/vector/branching/access.ipp b/src/immer/benchmark/vector/branching/access.ipp
new file mode 100644
index 0000000000000..bd7f985d4df05
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/access.ipp
@@ -0,0 +1,20 @@
+//
+// 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
+//
+
+#include "benchmark/vector/access.hpp"
+#include
+
+#ifndef MEMORY_T
+#error "define the MEMORY_T"
+#endif
+
+NONIUS_BENCHMARK("flex/3", benchmark_access_idx>())
+NONIUS_BENCHMARK("flex/4", benchmark_access_idx>())
+NONIUS_BENCHMARK("flex/5", benchmark_access_idx>())
+NONIUS_BENCHMARK("flex/6", benchmark_access_idx>())
+NONIUS_BENCHMARK("flex/7", benchmark_access_idx>())
diff --git a/src/immer/benchmark/vector/branching/assoc.ipp b/src/immer/benchmark/vector/branching/assoc.ipp
new file mode 100644
index 0000000000000..4aa9984f9275c
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/assoc.ipp
@@ -0,0 +1,20 @@
+//
+// 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
+//
+
+#include "benchmark/vector/assoc.hpp"
+#include
+
+#ifndef MEMORY_T
+#error "define the MEMORY_T"
+#endif
+
+NONIUS_BENCHMARK("flex/3", benchmark_assoc>())
+NONIUS_BENCHMARK("flex/4", benchmark_assoc>())
+NONIUS_BENCHMARK("flex/5", benchmark_assoc>())
+NONIUS_BENCHMARK("flex/6", benchmark_assoc>())
+NONIUS_BENCHMARK("flex/7", benchmark_assoc>())
diff --git a/src/immer/benchmark/vector/branching/basic/access.cpp b/src/immer/benchmark/vector/branching/basic/access.cpp
new file mode 100644
index 0000000000000..23eb25565da0c
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/basic/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T basic_memory
+#include "../access.ipp"
diff --git a/src/immer/benchmark/vector/branching/basic/assoc.cpp b/src/immer/benchmark/vector/branching/basic/assoc.cpp
new file mode 100644
index 0000000000000..210a432abab23
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/basic/assoc.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T basic_memory
+#include "../assoc.ipp"
diff --git a/src/immer/benchmark/vector/branching/basic/concat.cpp b/src/immer/benchmark/vector/branching/basic/concat.cpp
new file mode 100644
index 0000000000000..21163bdc0b942
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/basic/concat.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T basic_memory
+#include "../concat.ipp"
diff --git a/src/immer/benchmark/vector/branching/basic/push.cpp b/src/immer/benchmark/vector/branching/basic/push.cpp
new file mode 100644
index 0000000000000..6be28f9219f56
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/basic/push.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T basic_memory
+#include "../push.ipp"
diff --git a/src/immer/benchmark/vector/branching/concat.ipp b/src/immer/benchmark/vector/branching/concat.ipp
new file mode 100644
index 0000000000000..0e21ca0b111fc
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/concat.ipp
@@ -0,0 +1,20 @@
+//
+// 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
+//
+
+#include "benchmark/vector/concat.hpp"
+#include
+
+#ifndef MEMORY_T
+#error "define the MEMORY_T"
+#endif
+
+NONIUS_BENCHMARK("flex/3", benchmark_concat>())
+NONIUS_BENCHMARK("flex/4", benchmark_concat>())
+NONIUS_BENCHMARK("flex/5", benchmark_concat>())
+NONIUS_BENCHMARK("flex/6", benchmark_concat>())
+NONIUS_BENCHMARK("flex/7", benchmark_concat>())
diff --git a/src/immer/benchmark/vector/branching/gc/access.cpp b/src/immer/benchmark/vector/branching/gc/access.cpp
new file mode 100644
index 0000000000000..cec060481c737
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/gc/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T gc_memory
+#include "../access.ipp"
diff --git a/src/immer/benchmark/vector/branching/gc/assoc.cpp b/src/immer/benchmark/vector/branching/gc/assoc.cpp
new file mode 100644
index 0000000000000..448b2fd2ff79c
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/gc/assoc.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T gc_memory
+#include "../assoc.ipp"
diff --git a/src/immer/benchmark/vector/branching/gc/concat.cpp b/src/immer/benchmark/vector/branching/gc/concat.cpp
new file mode 100644
index 0000000000000..6c32ca821c8f4
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/gc/concat.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T gc_memory
+#include "../concat.ipp"
diff --git a/src/immer/benchmark/vector/branching/gc/push.cpp b/src/immer/benchmark/vector/branching/gc/push.cpp
new file mode 100644
index 0000000000000..f1d1e33b92437
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/gc/push.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T gc_memory
+#include "../push.ipp"
diff --git a/src/immer/benchmark/vector/branching/push.ipp b/src/immer/benchmark/vector/branching/push.ipp
new file mode 100644
index 0000000000000..2f92d6569220f
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/push.ipp
@@ -0,0 +1,20 @@
+//
+// 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
+//
+
+#include "benchmark/vector/push.hpp"
+#include
+
+#ifndef MEMORY_T
+#error "define the MEMORY_T"
+#endif
+
+NONIUS_BENCHMARK("flex/3", benchmark_push>())
+NONIUS_BENCHMARK("flex/4", benchmark_push>())
+NONIUS_BENCHMARK("flex/5", benchmark_push>())
+NONIUS_BENCHMARK("flex/6", benchmark_push>())
+NONIUS_BENCHMARK("flex/7", benchmark_push>())
diff --git a/src/immer/benchmark/vector/branching/safe/access.cpp b/src/immer/benchmark/vector/branching/safe/access.cpp
new file mode 100644
index 0000000000000..027aa1b7619ea
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/safe/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T safe_memory
+#include "../access.ipp"
diff --git a/src/immer/benchmark/vector/branching/safe/assoc.cpp b/src/immer/benchmark/vector/branching/safe/assoc.cpp
new file mode 100644
index 0000000000000..c2f5b0cc2034c
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/safe/assoc.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T safe_memory
+#include "../assoc.ipp"
diff --git a/src/immer/benchmark/vector/branching/safe/concat.cpp b/src/immer/benchmark/vector/branching/safe/concat.cpp
new file mode 100644
index 0000000000000..3c5dbb8a70a20
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/safe/concat.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T safe_memory
+#include "../concat.ipp"
diff --git a/src/immer/benchmark/vector/branching/safe/push.cpp b/src/immer/benchmark/vector/branching/safe/push.cpp
new file mode 100644
index 0000000000000..19d5bbd254ea8
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/safe/push.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T safe_memory
+#include "../push.ipp"
diff --git a/src/immer/benchmark/vector/branching/unsafe/access.cpp b/src/immer/benchmark/vector/branching/unsafe/access.cpp
new file mode 100644
index 0000000000000..156d84e717637
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/unsafe/access.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T unsafe_memory
+#include "../access.ipp"
diff --git a/src/immer/benchmark/vector/branching/unsafe/assoc.cpp b/src/immer/benchmark/vector/branching/unsafe/assoc.cpp
new file mode 100644
index 0000000000000..ff1802c0bc763
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/unsafe/assoc.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T unsafe_memory
+#include "../assoc.ipp"
diff --git a/src/immer/benchmark/vector/branching/unsafe/concat.cpp b/src/immer/benchmark/vector/branching/unsafe/concat.cpp
new file mode 100644
index 0000000000000..d6d401bd483de
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/unsafe/concat.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T unsafe_memory
+#include "../concat.ipp"
diff --git a/src/immer/benchmark/vector/branching/unsafe/push.cpp b/src/immer/benchmark/vector/branching/unsafe/push.cpp
new file mode 100644
index 0000000000000..09ba8d7a3759b
--- /dev/null
+++ b/src/immer/benchmark/vector/branching/unsafe/push.cpp
@@ -0,0 +1,10 @@
+//
+// 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
+//
+
+#define MEMORY_T unsafe_memory
+#include "../push.ipp"
diff --git a/src/immer/benchmark/vector/common.hpp b/src/immer/benchmark/vector/common.hpp
new file mode 100644
index 0000000000000..c96d6d017d9cb
--- /dev/null
+++ b/src/immer/benchmark/vector/common.hpp
@@ -0,0 +1,212 @@
+//
+// 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
+#include
+#include
+
+#include "benchmark/config.hpp"
+
+#if IMMER_BENCHMARK_LIBRRB
+extern "C" {
+#define restrict __restrict__
+#include
+#undef restrict
+}
+#include
+#endif
+
+namespace immer {
+template class array;
+} // namespace immer
+
+namespace {
+
+auto make_generator(std::size_t runs)
+{
+ assert(runs > 0);
+ auto engine = std::default_random_engine{42};
+ auto dist = std::uniform_int_distribution{0, runs-1};
+ auto r = std::vector(runs);
+ std::generate_n(r.begin(), runs, std::bind(dist, engine));
+ return r;
+}
+
+struct push_back_fn
+{
+ template
+ auto operator() (T&& v, U&& x)
+ { return std::forward(v).push_back(std::forward(x)); }
+};
+
+struct push_front_fn
+{
+ template
+ auto operator() (T&& v, U&& x)
+ { return std::forward(v).push_front(std::forward(x)); }
+};
+
+struct set_fn
+{
+ template
+ decltype(auto) operator() (T&& v, I i, U&& x)
+ { return std::forward(v).set(i, std::forward(x)); }
+};
+
+struct store_fn
+{
+ template