diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 48e2b6bee5..65dd192d90 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -15,7 +15,7 @@ jobs:
- name: Prepare
run: |
- sudo apt-get install libtool-bin libtomcrypt1 libtomcrypt-dev libtommath1 libtommath-dev libicu-dev zlib1g-dev
+ sudo apt-get install libtool-bin libtomcrypt1 libtomcrypt-dev libtommath1 libtommath-dev libicu-dev zlib1g-dev cmake
- name: Build
run: |
@@ -135,7 +135,7 @@ jobs:
fetch-depth: 10
- name: Prepare
- run: apk update && apk --no-cache --update add build-base libtool git autoconf automake zlib-dev icu-dev ncurses-dev libedit-dev linux-headers tar
+ run: apk update && apk --no-cache --update add build-base libtool git autoconf automake cmake zlib-dev icu-dev ncurses-dev libedit-dev linux-headers tar
- name: Build
run: |
@@ -323,7 +323,7 @@ jobs:
- name: Prepare - Install tools
run: |
- brew install automake libtool ninja
+ brew install automake cmake libtool ninja
- name: Cache - libc++ install
id: cache-libcxx-install-macos
diff --git a/.gitignore b/.gitignore
index 323f0838c1..23563ca04e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@ extern/ttmath/release/
/src/include/gen/parse.h
/src/include/gen/autoconfig.auto
/src/include/gen/autoconfig.h
+extern/libcds/lib/
diff --git a/appveyor.yml b/appveyor.yml
index 64ef3fc1ac..d229ecf49c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -28,7 +28,7 @@ install:
- cmd: cd builds\win32
- cmd: run_all.bat JUSTBUILD
- cmd: set ARTIFACTS_PATH=output_%FB_OUTPUT_SUFFIX%
- - sh: export APT_PACKAGES="libtool-bin"
+ - sh: export APT_PACKAGES="libtool-bin cmake"
- sh: if [ $PLATFORM = "x64" ]; then export APT_PACKAGES="$APT_PACKAGES libtommath1 libtommath-dev libicu-dev zlib1g-dev"; fi
- sh: if [ $PLATFORM = "x86" ]; then export APT_PACKAGES="$APT_PACKAGES gcc-multilib g++-multilib libncurses5-dev:i386 libtommath-dev:i386 libicu-dev:i386 zlib1g-dev:i386"; fi
- sh: if [ $PLATFORM = "x64" ]; then export CC="gcc" CXX="g++"; fi
diff --git a/builds/posix/Makefile.in b/builds/posix/Makefile.in
index a60c72a64a..4eeacb0934 100644
--- a/builds/posix/Makefile.in
+++ b/builds/posix/Makefile.in
@@ -83,6 +83,13 @@ LTC_LDFLAGS='-L$(LIB) $(subst $,$$$$,$(call LIB_LINK_RPATH,lib))'
endif
endif
+# correct build type for cmake builds
+FB_CMAKE_BUILD_TYPE=$(TARGET)
+ifeq ($(FB_CMAKE_BUILD_TYPE),Native)
+ FB_CMAKE_BUILD_TYPE=Release
+endif
+
+
.PHONY: master_process cross_process firebird Debug Release external
all: firebird
@@ -190,6 +197,8 @@ ifeq ($(RE2_BUILD_FLG),Y)
ln -sf $(ROOT)/extern/re2/obj/libre2.a $(LIB)
endif
+ $(MAKE) libcds
+
ifeq ($(TOMMATH_BUILD_FLG),Y)
CC="$(CC)" CFLAGS="$(CFLAGS)" AR="$(AR)" $(MAKE) -C $(ROOT)/extern/libtommath -f makefile.shared GCC="$(CC)"
@@ -279,6 +288,23 @@ $(RE2_LIB): $(RE2_Objs)
-$(RM) $@
$(STATICLIB_LINK) $@ $^
+#___________________________________________________________________________
+# libcds
+#
+
+.PHONY: libcds
+libcds:
+ mkdir -p $(LIBCDS)/lib/$(TARGET)
+ cd $(LIBCDS)/lib/$(TARGET); \
+ cmake -DCMAKE_BUILD_TYPE=$(FB_CMAKE_BUILD_TYPE) -DCMAKE_CXX_FLAGS=-fPIC $(LIBCDS)
+ AR="$(AR)" $(MAKE) -C $(LIBCDS)/lib/$(TARGET)
+
+ifeq ($(TARGET),Debug)
+ ln -sf $(LIBCDS)/lib/$(TARGET)/bin/libcds-s_d.a $(LIB)/libcds.a
+else
+ ln -sf $(LIBCDS)/lib/$(TARGET)/bin/libcds-s.a $(LIB)/libcds.a
+endif
+
#___________________________________________________________________________
# main build target for both debug and release builds
#
@@ -343,6 +369,7 @@ cross2:
ln -sf $(ROOT)/extern/decNumber/libdecFloat$(CROSS).a $(LIB)
CXX="$(CXX)" CXXFLAGS="$(CXXFLAGS)" $(MAKE) -C $(ROOT)/extern/int128/absl/numeric
ln -sf $(ROOT)/extern/int128/absl/numeric/libi128$(CROSS).a $(LIB)
+ $(MAKE) libcds
$(MAKE) yvalve
$(MAKE) engine
$(MAKE) fbintl
diff --git a/builds/posix/make.android.arm64 b/builds/posix/make.android.arm64
index 0e25b3e300..f64947c531 100644
--- a/builds/posix/make.android.arm64
+++ b/builds/posix/make.android.arm64
@@ -41,7 +41,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS)
CROSS_CONFIG=android.arm64
LDFLAGS += -static-libstdc++
-DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB)
+DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
UDR_SUPPORT_LIBS :=
LINK_LIBS = $(DroidLibs)
diff --git a/builds/posix/make.android.arme b/builds/posix/make.android.arme
index cbf56253f6..b4b597d8e3 100644
--- a/builds/posix/make.android.arme
+++ b/builds/posix/make.android.arme
@@ -41,7 +41,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS)
CROSS_CONFIG=android.arme
LDFLAGS += -static-libstdc++
-DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB)
+DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
UDR_SUPPORT_LIBS :=
LINK_LIBS = $(DroidLibs)
diff --git a/builds/posix/make.android.x86 b/builds/posix/make.android.x86
index 1344fe0dc1..a1dcd58368 100644
--- a/builds/posix/make.android.x86
+++ b/builds/posix/make.android.x86
@@ -41,7 +41,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS)
CROSS_CONFIG=android.x86
LDFLAGS += -static-libstdc++
-DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB)
+DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
UDR_SUPPORT_LIBS :=
LINK_LIBS = $(DroidLibs)
diff --git a/builds/posix/make.android.x86_64 b/builds/posix/make.android.x86_64
index 34ae36925d..15df6dac61 100644
--- a/builds/posix/make.android.x86_64
+++ b/builds/posix/make.android.x86_64
@@ -41,7 +41,7 @@ DEV_FLAGS=$(COMMON_FLAGS) $(WARN_FLAGS)
CROSS_CONFIG=android.x86_64
LDFLAGS += -static-libstdc++
-DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB)
+DroidLibs := -lm -ldl $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
UDR_SUPPORT_LIBS :=
LINK_LIBS = $(DroidLibs)
diff --git a/builds/posix/make.defaults b/builds/posix/make.defaults
index 44290a5451..fab49ceac9 100755
--- a/builds/posix/make.defaults
+++ b/builds/posix/make.defaults
@@ -148,6 +148,8 @@ else
I128LIB=
endif
+LIBCDSLIB=-lcds
+
# crypt library
CRYPTLIB=@CRYPTLIB@
@@ -204,8 +206,8 @@ endif
STATICLIB_LINK = $(AR) crus
-LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB)
-SO_LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB)
+LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
+SO_LINK_LIBS = @LIBS@ $(DECLIB) $(RE2LIB) $(I128LIB) $(LIBCDSLIB)
# Default extensions
@@ -294,6 +296,11 @@ TOMCRYPT_INC=$(TOMCRYPT)/src/headers
TOMCRYPT_SO=$(TOMCRYPT)/.libs/libtomcrypt.so
TOMCRYPT_VER=1
+# Own libcds support
+LIBCDS=$(ROOT)/extern/libcds
+LIBCDS_INC=$(LIBCDS)
+LIBCDS_DEF=CDS_BUILD_STATIC_LIB
+
# LINKER OPTIONS
#
diff --git a/builds/posix/make.rules b/builds/posix/make.rules
index 997981cdb5..69b40e6411 100644
--- a/builds/posix/make.rules
+++ b/builds/posix/make.rules
@@ -38,6 +38,8 @@ ifneq ($(SYSTEM_BOOST_FLG),Y)
WFLAGS += -I$(ROOT)/extern/boost
endif
+WFLAGS += -I$(LIBCDS_INC) -D$(LIBCDS_DEF)
+
ifeq ($(TOMMATH_BUILD_FLG),Y)
WFLAGS += -I$(TOMMATH_INC)
endif
diff --git a/builds/win32/clean_all.bat b/builds/win32/clean_all.bat
index 3cf5d940eb..0c0c2e111e 100644
--- a/builds/win32/clean_all.bat
+++ b/builds/win32/clean_all.bat
@@ -22,6 +22,16 @@ for %%v in ( %* ) do (
@echo Cleaning icu...
@rmdir /S /Q "%FB_ROOT_PATH%\extern\icu\%FB_TARGET_PLATFORM%\%FBBUILD_BUILDTYPE%" 2>nul
+@echo Cleaning cds...
+@for /D %%d in ("%FB_ROOT_PATH%\extern\libcds\obj\*") do (
+ rmdir /S /Q "%%d\%FB_TARGET_PLATFORM%\cds\%FB_CONFIG%-static" 2>nul
+)
+
+@for /D %%d in ("%FB_ROOT_PATH%\extern\libcds\bin\*") do (
+ rmdir /S /Q "%%d\%FB_TARGET_PLATFORM%-%FB_CONFIG%-static" 2>nul
+)
+
+
@echo Cleaning decNumber...
@rmdir /S /Q "%FB_ROOT_PATH%\extern\decNumber\lib\%FB_TARGET_PLATFORM%" 2>nul
@rmdir /S /Q "%FB_ROOT_PATH%\extern\decNumber\temp\%FB_TARGET_PLATFORM%" 2>nul
diff --git a/builds/win32/compile.bat b/builds/win32/compile.bat
index 07ae6415e0..fe3811137c 100644
--- a/builds/win32/compile.bat
+++ b/builds/win32/compile.bat
@@ -18,6 +18,11 @@ set projects=
set config=debug
)
+:: Special case for CDS, set in make_boot only
+@if "%FB_LIBCDS%"=="1" (
+ set config=%config%-static
+)
+
shift
shift
diff --git a/builds/win32/make_boot.bat b/builds/win32/make_boot.bat
index 54eaa3036e..6fae14afe1 100644
--- a/builds/win32/make_boot.bat
+++ b/builds/win32/make_boot.bat
@@ -34,6 +34,9 @@ if "%ERRLEV%"=="1" goto :END
call :btyacc
if "%ERRLEV%"=="1" goto :END
+call :libcds
+if "%ERRLEV%"=="1" goto :END
+
call :LibTom
if "%ERRLEV%"=="1" goto :END
@@ -145,6 +148,17 @@ goto :EOF
if errorlevel 1 call :boot2 decNumber_%FB_OBJ_DIR%
goto :EOF
+::===================
+:: Build libcds
+:libcds
+@echo.
+set FB_LIBCDS=1
+@echo Building libcds (%FB_OBJ_DIR%)...
+@call compile.bat extern\libcds\projects\Win\vc141\cds libcds_%FB_CONFIG%_%FB_TARGET_PLATFORM%.log cds
+if errorlevel 1 call :boot2 libcds%FB_OBJ_DIR%
+set FB_LIBCDS=
+goto :EOF
+
::===================
:: BUILD ttmath
:ttmath
diff --git a/builds/win32/msvc15/engine.vcxproj b/builds/win32/msvc15/engine.vcxproj
index 029028aef2..49d3df52cf 100644
--- a/builds/win32/msvc15/engine.vcxproj
+++ b/builds/win32/msvc15/engine.vcxproj
@@ -113,24 +113,28 @@
+
+
+
+
diff --git a/builds/win32/msvc15/engine_static.vcxproj b/builds/win32/msvc15/engine_static.vcxproj
index 3981c1776e..72aa1a3029 100644
--- a/builds/win32/msvc15/engine_static.vcxproj
+++ b/builds/win32/msvc15/engine_static.vcxproj
@@ -89,6 +89,7 @@
+
@@ -276,6 +277,7 @@
+
@@ -429,24 +431,28 @@
+
+
+
+
diff --git a/builds/win32/msvc15/engine_static.vcxproj.filters b/builds/win32/msvc15/engine_static.vcxproj.filters
index f068282124..e0f9907b7b 100644
--- a/builds/win32/msvc15/engine_static.vcxproj.filters
+++ b/builds/win32/msvc15/engine_static.vcxproj.filters
@@ -513,6 +513,9 @@
JRD files
+
+ JRD files
+ Optimizer
@@ -1070,6 +1073,9 @@
Header files
+
+ Header files
+ Header files
diff --git a/builds/win32/msvc15/engine_test.vcxproj b/builds/win32/msvc15/engine_test.vcxproj
index 312f7dd1e3..3a36737af0 100644
--- a/builds/win32/msvc15/engine_test.vcxproj
+++ b/builds/win32/msvc15/engine_test.vcxproj
@@ -66,24 +66,28 @@
+
+
+
+
diff --git a/builds/win32/msvc15/fbserver.vcxproj b/builds/win32/msvc15/fbserver.vcxproj
index 374e17da36..8236adbbbe 100644
--- a/builds/win32/msvc15/fbserver.vcxproj
+++ b/builds/win32/msvc15/fbserver.vcxproj
@@ -239,4 +239,4 @@
-
+
\ No newline at end of file
diff --git a/builds/win32/msvc15/libcds.props b/builds/win32/msvc15/libcds.props
new file mode 100644
index 0000000000..dd481dee9f
--- /dev/null
+++ b/builds/win32/msvc15/libcds.props
@@ -0,0 +1,23 @@
+
+
+
+
+ ..\..\..\extern\libcds
+
+
+
+
+ $(LIBCDS_ROOT);%(AdditionalIncludeDirectories)
+ CDS_BUILD_STATIC_LIB;%(PreprocessorDefinitions)
+
+
+ $(LIBCDS_ROOT)\bin\vc.$(PlatformToolset)\$(Platform)-$(Configuration)-static;%(AdditionalLibraryDirectories)
+ libcds-$(PlatformTarget).lib;%(AdditionalDependencies)
+
+
+
+
+ $(LIBCDS_ROOT)
+
+
+
diff --git a/extern/libcds/.gitignore b/extern/libcds/.gitignore
new file mode 100644
index 0000000000..a4086f1356
--- /dev/null
+++ b/extern/libcds/.gitignore
@@ -0,0 +1,21 @@
+/doc
+/sandbox
+*.o
+*.d
+/bin
+/obj
+/projects/Win/vc14/cds.sdf
+/projects/Win/vc14/cds.v14.suo
+/projects/Win/vc14/*.user
+/projects/Win/vc14/*.opensdf
+/projects/Win/vc14/.vs/
+/projects/Win/vc141/.vs/
+/projects/Win/vc141/*.user
+*.log
+/.project
+/projects/Win/vc14/*.opendb
+/test/stress/data/dictionary.txt
+/projects/Win/vc14/cds.VC.db
+/.cproject
+/.settings/
+/tools/change_license.pl
diff --git a/extern/libcds/.travis.yml b/extern/libcds/.travis.yml
new file mode 100644
index 0000000000..91028597b6
--- /dev/null
+++ b/extern/libcds/.travis.yml
@@ -0,0 +1,265 @@
+language: cpp
+
+install:
+ - chmod +x ./build/CI/travis-ci/install.sh
+ - ./build/CI/travis-ci/install.sh
+
+script:
+ - chmod +x ./build/CI/travis-ci/run.sh
+ - ./build/CI/travis-ci/run.sh
+
+linux: &linux_gcc
+ os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-6
+ compiler:
+ - g++-6
+ before_install:
+ - eval "CC=gcc-6 && CXX=g++-6"
+
+
+linux: &linux_clang
+ os: linux
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ - llvm-toolchain-trusty-4.0
+ packages:
+ - clang-4.0
+ compiler:
+ - clang-4.0
+ before_install:
+ - eval "CC=clang-4.0 && CXX=clang++-4.0"
+
+
+osx: &osx
+ os: osx
+ osx_image: xcode8.3
+ compiler:
+ - clang
+ before_install:
+ - eval "CC=clang && CXX=clang++"
+
+
+matrix:
+ include:
+## BUILD_TYPE=Release CXX_COMPILER=g++-6
+ - <<: *linux_gcc
+ env: TARGET=unit-deque BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-ilist BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-list BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-map BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-misc BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-pqueue BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-queue BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-feldman BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-michael-michael BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-michael-lazy BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-michael-iterable BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-skip BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-split-michael BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-split-lazy BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-iset-split-iterable BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-set BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-striped-set BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-stack BUILD_TYPE=Release
+ - <<: *linux_gcc
+ env: TARGET=unit-tree BUILD_TYPE=Release
+
+## BUILD_TYPE=Debug CXX_COMPILER=g++-6
+ - <<: *linux_gcc
+ env: TARGET=unit-deque BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-ilist BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-list BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-map BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-misc BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-pqueue BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-queue BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-iset BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-set BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-striped-set BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-stack BUILD_TYPE=Debug
+ - <<: *linux_gcc
+ env: TARGET=unit-tree BUILD_TYPE=Debug
+
+## BUILD_TYPE=Release CXX_COMPILER=clang-4.0
+ - <<: *linux_clang
+ env: TARGET=unit-deque BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-ilist BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-list BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-misc BUILD_TYPE=Release LINKER_FLAGS=-latomic
+ - <<: *linux_clang
+ env: TARGET=unit-pqueue BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-queue BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-feldman BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-michael-michael BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-michael-iterable BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-michael-lazy BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-skip BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-split-iterable BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-split-michael BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-set-split-lazy BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-striped-set BUILD_TYPE=Release
+ - <<: *linux_clang
+ env: TARGET=unit-stack BUILD_TYPE=Release
+# FIXME: building too long. Travis-ci will stop building.
+# - BUILD_TYPE=Release TARGET=unit-map
+# - BUILD_TYPE=Release TARGET=unit-iset
+# - BUILD_TYPE=Release TARGET=unit-tree
+
+## BUILD_TYPE=Debug CXX_COMPILER=clang-4.0
+ - <<: *linux_clang
+ env: TARGET=unit-deque BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-ilist BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-list BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-map BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-misc BUILD_TYPE=Debug LINKER_FLAGS=-latomic
+ - <<: *linux_clang
+ env: TARGET=unit-pqueue BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-queue BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-iset BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-set BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-striped-set BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-stack BUILD_TYPE=Debug
+ - <<: *linux_clang
+ env: TARGET=unit-tree BUILD_TYPE=Debug
+
+# RELEASE
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-deque
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-ilist
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-list
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-misc
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-pqueue
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-queue
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-feldman
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-michael-michael
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-michael-lazy
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-michael-iterable
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-skip
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-split-michael
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-split-lazy
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-iset-split-iterable
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-striped-set
+ - <<: *osx
+ env: BUILD_TYPE=Release TARGET=unit-stack
+# FIXME: building too long. Travis-ci will stop building.
+# - <<: *osx
+# env: BUILD_TYPE=Release TARGET=unit-map
+# - <<: *osx
+# env: BUILD_TYPE=Release TARGET=unit-set
+# - <<: *osx
+# env: BUILD_TYPE=Release TARGET=unit-tree
+
+# DEBUG
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-deque
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-ilist
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-list
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-map
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-misc
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-pqueue
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-queue
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-feldman
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-michael-michael
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-michael-lazy
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-michael-iterable
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-skip
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-split-michael
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-split-lazy
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-iset-split-iterable
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-set
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-striped-set
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-stack
+ - <<: *osx
+ env: BUILD_TYPE=Debug TARGET=unit-tree
+
diff --git a/extern/libcds/CMakeLists.txt b/extern/libcds/CMakeLists.txt
new file mode 100644
index 0000000000..d97ee073ca
--- /dev/null
+++ b/extern/libcds/CMakeLists.txt
@@ -0,0 +1,250 @@
+cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
+
+cmake_policy(SET CMP0016 NEW)
+if(POLICY CMP0042)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/cmake ${CMAKE_MODULE_PATH})
+include(TargetArch)
+include(CheckIncludeFileCXX)
+
+project(cds)
+
+set(PROJECT_VERSION 2.3.3)
+
+# Options
+option(WITH_TESTS "Build unit tests" OFF)
+option(WITH_TESTS_COVERAGE "Analyze test coverage using gcov (only for gcc)" OFF)
+option(WITH_BOOST_ATOMIC "Use boost atomics (only for boost >= 1.54)" OFF)
+option(WITH_ASAN "Build ASan+UBSan instrumented code" OFF)
+option(WITH_TSAN "Build TSan instrumented code" OFF)
+option(ENABLE_UNIT_TEST "Enable unit test" ON)
+option(ENABLE_STRESS_TEST "Enable stress test" ON)
+set(CMAKE_TARGET_ARCHITECTURE "" CACHE string "Target build architecture")
+
+find_package(Threads)
+
+if(NOT CMAKE_TARGET_ARCHITECTURE)
+ target_architecture(CMAKE_TARGET_ARCHITECTURE)
+endif()
+
+if(APPLE)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DARWIN_C_SOURCE")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_DARWIN_C_SOURCE")
+endif()
+
+if(WITH_BOOST_ATOMIC)
+ if(TARGET boost::atomic)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCDS_USE_BOOST_ATOMIC")
+ link_libraries(boost::atomic)
+ else()
+ find_package(Boost 1.53 COMPONENTS atomic)
+ if(Boost_FOUND)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCDS_USE_BOOST_ATOMIC")
+ message(STATUS "Boost version allows using of boost.atomic: activated")
+ endif()
+ endif()
+endif(WITH_BOOST_ATOMIC)
+
+if(WITH_ASAN)
+ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -fPIC -fsanitize=address,undefined -g -DCDS_ADDRESS_SANITIZER_ENABLED -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -fsanitize=address,undefined -g -DCDS_ASAN_ENABLED -fno-omit-frame-pointer -fno-optimize-sibling-calls")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -pie")
+ else()
+ message(WARNING "Compiler does not support AddressSanitizer")
+ endif()
+endif(WITH_ASAN)
+
+if(WITH_TSAN)
+ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_CXX_FLAGS_DEBUG "-D_DEBUG")
+ set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O1 -fPIC -fsanitize=thread -g -DCDS_THREAD_SANITIZER_ENABLED -fno-omit-frame-pointer")
+ set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -O1 -fPIC -fsanitize=thread -g -DCDS_THREAD_SANITIZER_ENABLED -fno-omit-frame-pointer")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread -pie")
+ else()
+ message(WARNING "Compiler does not support ThreadSanitizer")
+ endif()
+endif(WITH_TSAN)
+
+if(WITH_TESTS_COVERAGE)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+ message(STATUS "Test coverage analysis: activated")
+ else()
+ message(WARNING "Compiler is not GNU gcc! Test coverage couldn't be analyzed")
+ endif()
+endif(WITH_TESTS_COVERAGE)
+
+set(CDS_SHARED_LIBRARY ${PROJECT_NAME})
+set(CDS_STATIC_LIBRARY ${PROJECT_NAME}-s)
+
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+if(CDS_BIN_DIR)
+ set(EXECUTABLE_OUTPUT_PATH ${CDS_BIN_DIR})
+ set(LIBRARY_OUTPUT_PATH ${CDS_BIN_DIR})
+else()
+ set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+ set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+endif()
+message(STATUS "Binary output path: ${EXECUTABLE_OUTPUT_PATH}")
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Debug CACHE STRING "Default build type to Debug" FORCE)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ string(REGEX MATCHALL "-std=[^ ]+" cxx_std_found ${CMAKE_CXX_FLAGS} " dummy@rg")
+ if(cxx_std_found)
+ message("C++ std: ${cxx_std_found}")
+ else()
+ list(APPEND LIBCDS_PUBLIC_CXX_FLAGS "-std=c++11")
+ message("C++ std: -std=c++11 (default)")
+ endif()
+
+ list(APPEND LIBCDS_PRIVATE_CXX_FLAGS "-Wall" "-Wextra" "-pedantic")
+
+ if(CMAKE_TARGET_ARCHITECTURE STREQUAL "x86_64")
+ list(APPEND LIBCDS_PUBLIC_CXX_FLAGS "-mcx16")
+ set(LIB_SUFFIX "64")
+
+ # GCC-7: 128-bit atomics support is implemented via libatomic on amd64
+ # see https://gcc.gnu.org/ml/gcc/2017-01/msg00167.html
+ # Maybe, it will be changed in future
+ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "7.0.0" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.0.0")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -latomic")
+ endif()
+ endif()
+endif()
+
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ set(CMAKE_CXX_ARCHIVE_CREATE " -q -c ${CMAKE_STATIC_LINKER_FLAGS} -o ")
+ list(APPEND LIBCDS_PRIVATE_CXX_FLAGS "-Wl,-G")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-brtl")
+endif()
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")
+
+CHECK_INCLUDE_FILE_CXX(linux/membarrier.h CDS_HAVE_LINUX_MEMBARRIER_H CMAKE_CXX_FLAGS)
+
+message("Build type -- ${CMAKE_BUILD_TYPE}")
+message("Compiler version: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
+message("System: ${CMAKE_SYSTEM_NAME} version: ${CMAKE_SYSTEM_VERSION}")
+message("Target architecture: ${CMAKE_TARGET_ARCHITECTURE}")
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message("Compiler flags: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG} ${LIBCDS_PUBLIC_CXX_FLAGS} ${LIBCDS_PRIVATE_CXX_FLAGS}")
+else()
+ message("Compiler flags: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} ${LIBCDS_PUBLIC_CXX_FLAGS} ${LIBCDS_PRIVATE_CXX_FLAGS}")
+endif()
+message("Exe flags: ${CMAKE_EXE_LINKER_FLAGS}")
+
+# Component names for separate distribution in rpms, debs etc.
+set(LIBRARIES_COMPONENT lib)
+set(HEADERS_COMPONENT devel)
+
+set(SOURCES src/init.cpp
+ src/hp.cpp
+ src/dhp.cpp
+ src/urcu_gp.cpp
+ src/urcu_sh.cpp
+ src/thread_data.cpp
+ src/topology_hpux.cpp
+ src/topology_linux.cpp
+ src/topology_osx.cpp
+ src/dllmain.cpp)
+
+add_library(${CDS_SHARED_LIBRARY} SHARED ${SOURCES})
+set_target_properties(${CDS_SHARED_LIBRARY} PROPERTIES VERSION ${PROJECT_VERSION}
+ DEBUG_POSTFIX "_d")
+if(MINGW)
+ set_target_properties(${CDS_SHARED_LIBRARY} PROPERTIES DEFINE_SYMBOL CDS_BUILD_LIB)
+endif()
+
+add_library(${CDS_STATIC_LIBRARY} STATIC ${SOURCES})
+set_target_properties(${CDS_STATIC_LIBRARY} PROPERTIES DEBUG_POSTFIX "_d")
+if(MINGW)
+ target_compile_definitions(${CDS_STATIC_LIBRARY} PRIVATE CDS_BUILD_STATIC_LIB)
+endif()
+
+target_link_libraries(${CDS_SHARED_LIBRARY} PRIVATE ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries(${CDS_STATIC_LIBRARY} PRIVATE ${CMAKE_THREAD_LIBS_INIT})
+target_include_directories(${CDS_SHARED_LIBRARY} INTERFACE "$"
+ $)
+target_include_directories(${CDS_STATIC_LIBRARY} INTERFACE "$"
+ $)
+target_compile_options(${CDS_SHARED_LIBRARY} PUBLIC "${LIBCDS_PUBLIC_CXX_FLAGS}")
+target_compile_options(${CDS_STATIC_LIBRARY} PUBLIC "${LIBCDS_PUBLIC_CXX_FLAGS}")
+target_compile_options(${CDS_SHARED_LIBRARY} PRIVATE "${LIBCDS_PRIVATE_CXX_FLAGS}")
+target_compile_options(${CDS_STATIC_LIBRARY} PRIVATE "${LIBCDS_PRIVATE_CXX_FLAGS}")
+
+install(TARGETS ${CDS_SHARED_LIBRARY} EXPORT LibCDSConfig LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT ${LIBRARIES_COMPONENT} NAMELINK_SKIP RUNTIME DESTINATION lib${LIB_SUFFIX})
+install(TARGETS ${CDS_SHARED_LIBRARY} EXPORT LibCDSConfig LIBRARY DESTINATION lib${LIB_SUFFIX} COMPONENT ${HEADERS_COMPONENT} NAMELINK_ONLY)
+install(TARGETS ${CDS_STATIC_LIBRARY} EXPORT LibCDSConfig DESTINATION lib${LIB_SUFFIX} COMPONENT ${LIBRARIES_COMPONENT})
+install(EXPORT LibCDSConfig FILE LibCDSConfig.cmake NAMESPACE LibCDS:: DESTINATION lib/cmake/LibCDS)
+install(DIRECTORY ${PROJECT_SOURCE_DIR}/cds DESTINATION include COMPONENT ${HEADERS_COMPONENT})
+
+if(WITH_TESTS)
+ enable_testing()
+ add_subdirectory(${PROJECT_SOURCE_DIR}/test)
+ message(STATUS "Build tests: activated")
+endif(WITH_TESTS)
+
+### FOR PACKAGING in RPM, TGZ, DEB, NSYS...###############################################################################
+set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
+set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
+set(CPACK_PACKAGE_CONTACT "Max Khizhinsky ")
+set(CPACK_PACKAGE_RELEASE 1)
+set(CPACK_PACKAGE_INSTALL_DIRECTORY "cds")
+set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/build/cmake/description.txt")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Library of concurrent data structures")
+set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_RELEASE}")
+set(DEPLOY_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
+
+# TGZ specific
+set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+
+# RPM specific
+set(CPACK_RPM_COMPONENT_INSTALL ON)
+set(CPACK_RPM_PACKAGE_RELEASE ${CPACK_PACKAGE_RELEASE})
+set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/build/cmake/post_install_script.sh")
+set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/build/cmake/post_uninstall_script.sh")
+set(CPACK_RPM_PACKAGE_URL https://github.com/khizmax/libcds)
+set(CPACK_RPM_PACKAGE_LICENSE GPL)
+set(CPACK_RPM_PACKAGE_GROUP "System Environment/Base")
+set(CPACK_RPM_PACKAGE_REQUIRES "boost >= 1.50")
+set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION ${CPACK_PACKAGING_INSTALL_PREFIX})
+set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/local)
+set(CPACK_RPM_devel_PACKAGE_REQUIRES "boost >= 1.50, cds-lib = ${PROJECT_VERSION}")
+
+# DEB specific
+set(CPACK_DEB_COMPONENT_INSTALL ON)
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "boost (>= 1.50)")
+set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://github.com/khizmax/libcds")
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${PROJECT_SOURCE_DIR}/build/cmake/post_install_script.sh;;${PROJECT_SOURCE_DIR}/build/cmake/post_uninstall_script.sh;")
+
+# NSYS specific
+set(CPACK_NSIS_PACKAGE_NAME "${CPACK_PACKAGE_NAME}")
+set(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_NAME}")
+set(CPACK_NSIS_CONTACT ${CPACK_PACKAGE_CONTACT})
+set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
+set(CPACK_NSIS_MODIFY_PATH ON)
+
+# Components grouping for Mac OS X and Windows installers
+set(CPACK_COMPONENT_${LIBRARIES_COMPONENT}_GROUP "Runtime")
+set(CPACK_COMPONENT_${HEADERS_COMPONENT}_GROUP "Development")
+set(CPACK_COMPONENT_${LIBRARIES_COMPONENT}_DISPLAY_NAME "Libraries")
+set(CPACK_COMPONENT_${HEADERS_COMPONENT}_DISPLAY_NAME "C++ Headers")
+set(CPACK_COMPONENT_${HEADERS_COMPONENT}_DEPENDS ${LIBRARIES_COMPONENT})
+set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION "All of the tools you'll ever need to develop lock-free oriented software with libcds")
+set(CPACK_COMPONENT_GROUP_RUNTIME_DESCRIPTION "Only libcds library for runtime")
+
+include(CPack)
diff --git a/extern/libcds/LICENSE b/extern/libcds/LICENSE
new file mode 100644
index 0000000000..127a5bc39b
--- /dev/null
+++ b/extern/libcds/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.
\ No newline at end of file
diff --git a/extern/libcds/appveyor.yml b/extern/libcds/appveyor.yml
new file mode 100644
index 0000000000..e50eaa9a78
--- /dev/null
+++ b/extern/libcds/appveyor.yml
@@ -0,0 +1,91 @@
+build: false
+
+shallow_clone: true # (git clone --depth 1)
+
+image:
+ - Visual Studio 2017
+
+install:
+ - sed -i "/boost/d" conanfile.txt # delete boost from conanfile. Conan renamed name of boost libs so we'll use appveyour's boost
+ - cmd: echo "Downloading conan..."
+ - cmd: set PATH=%PATH%;%PYTHON%/Scripts/
+ - cmd: pip.exe install conan
+ - cmd: conan user # Create the conan data directory
+ - cmd: conan --version
+ - cmd: conan install --build=missing -s arch=x86 -s build_type=%configuration% .
+ #- cmd: conan install --build=missing -s arch=x86_64 -s build_type=%configuration% conanfileWin.txt
+ - cmd: echo =======================
+ - cmd: echo %configuration%
+ - cmd: echo %platform%
+ - cmd: echo =======================
+ - cmd: set GTEST_ROOT=C:/projects/libcds/deps
+ - cmd: set BOOST_PATH=C:\Libraries\boost_1_66_0
+ - cmd: set GTEST_LIB32=C:\projects\libcds\deps\lib;C:\Libraries\boost_1_66_0\lib32-msvc-14.1
+ - cmd: dir %GTEST_LIB32%
+ - cmd: echo =======================
+ # - cmd: set GTEST_LIB64=C:\projects\libcds\deps\lib
+
+
+environment:
+ matrix:
+ # require a library with name libboost_thread-vc141-mt-x32-1_66.lib,
+ - TARGET: gtest-stack
+ - TARGET: gtest-deque
+ - TARGET: gtest-pqueue
+ - TARGET: gtest-queue
+
+ - TARGET: gtest-map-skip
+ - TARGET: gtest-map-split-michael
+ - TARGET: gtest-set-split-michael
+ - TARGET: gtest-misc
+ - TARGET: gtest-ilist-iterable
+ - TARGET: gtest-ilist-lazy
+ - TARGET: gtest-ilist-michael
+ - TARGET: gtest-iset-feldman
+ - TARGET: gtest-iset-michael
+ - TARGET: gtest-iset-michael-iterable
+ - TARGET: gtest-iset-michael-lazy
+ - TARGET: gtest-iset-skip
+ - TARGET: gtest-iset-split-iterable
+ - TARGET: gtest-iset-split-lazy
+ - TARGET: gtest-iset-split-michael
+ - TARGET: gtest-list-iterable
+ - TARGET: gtest-list-lazy
+ - TARGET: gtest-list-michael
+ - TARGET: gtest-map-feldman
+ - TARGET: gtest-map-michael
+ - TARGET: gtest-map-michael-iterable
+ - TARGET: gtest-map-michael-lazy
+ - TARGET: gtest-map-split-iterable
+ - TARGET: gtest-map-split-lazy
+ - TARGET: gtest-set-feldman
+ - TARGET: gtest-set-michael
+ - TARGET: gtest-set-michael-iterable
+ - TARGET: gtest-set-michael-lazy
+ - TARGET: gtest-set-skip
+ - TARGET: gtest-set-split-iterable
+ - TARGET: gtest-set-split-lazy
+ - TARGET: gtest-striped-map-boost
+ - TARGET: gtest-striped-map-cuckoo
+ - TARGET: gtest-striped-map-std
+ - TARGET: gtest-striped-set-boost
+ - TARGET: gtest-striped-set-cuckoo
+ - TARGET: gtest-striped-set-std
+ - TARGET: gtest-tree-bronson
+ - TARGET: gtest-tree-ellen
+configuration:
+ - Release
+platform:
+ - Win32
+
+build_script:
+ - msbuild projects/Win/vc141/cds.vcxproj /p:Configuration=%configuration% /p:PlatformTarget="Win32"
+ - msbuild projects/Win/vc141/%TARGET%.vcxproj /p:Configuration=%configuration% /p:PlatformTarget="Win32"
+ #- msbuild projects/Win/vc141/cds.vcxproj /p:Configuration=%configuration% /p:PlatformTarget=x64
+ #- msbuild projects/Win/vc141/%TARGET%.vcxproj /p:Configuration=%configuration% /p:PlatformTarget=x64
+
+test_script:
+ - cmd: set path=%path%;%GTEST_LIB32%;C:\projects\libcds\bin\vc.v141\%platform%-release\
+ - cmd: C:\projects\libcds\bin\vc.v141\%platform%-release\%TARGET%.exe
+
+
diff --git a/extern/libcds/build/CI/VASEx-CI-2/cds-libs b/extern/libcds/build/CI/VASEx-CI-2/cds-libs
new file mode 100644
index 0000000000..de125daefb
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI-2/cds-libs
@@ -0,0 +1,239 @@
+#########################################
+# Generic parameters
+
+workspace: $WORKSPACE
+libcds-source: source
+make-job: 10
+gtest-include: $GTEST_ROOT/googletest/include
+
+#########################################
+#GCC-4.8
+gcc-4.8-root: $GCC48_ROOT/bin
+gcc-4.8-cxx: g++-4.8
+gcc-4.8-cc: gcc-4.8
+gcc-4.8-exe-ldflags: -L$GCC48_ROOT/lib64 -Wl,-rpath=$GCC48_ROOT/lib64
+gcc-4.8-extlib: rt
+gcc-4.8-boost: $BOOST_ROOT
+gcc-4.8-64-boost-lib: stage64-gcc4.8/lib
+gcc-4.8-gtest: $GTEST_ROOT
+gcc-4.8-64-gtest-lib: $GTEST_ROOT/lib-gcc4.8/libgtest.a
+
+
+########################################
+#GCC-4.9
+gcc-4.9-root: $GCC49_ROOT/bin
+gcc-4.9-cxx: g++-4.9
+gcc-4.9-cc: gcc-4.9
+gcc-4.9-exe-ldflags: -Wl,-rpath=$GCC49_ROOT/lib64
+gcc-4.9-extlib: rt
+gcc-4.9-boost: $BOOST_ROOT
+gcc-4.9-64-boost-lib: stage64-gcc4.9/lib
+gcc-4.9-gtest: $GTEST_ROOT
+gcc-4.9-64-gtest-lib: $GTEST_ROOT/lib-gcc4.9/libgtest.a
+
+########################################
+#GCC-5
+gcc-5-root: $GCC5_ROOT/bin
+gcc-5-cxx: g++-5
+gcc-5-cc: gcc-5
+gcc-5-boost: $BOOST_ROOT
+gcc-5-exe-ldflags: -Wl,-rpath=$GCC5_ROOT/lib64
+gcc-5-extlib: rt
+gcc-5-64-boost-lib: stage64-gcc5/lib
+gcc-5-64-asan-boost-lib: stage64-gcc5-asan/lib
+gcc-5-64-tsan-boost-lib: stage64-gcc5-tsan/lib
+gcc-5-gtest: $GTEST_ROOT
+gcc-5-64-gtest-lib: $GTEST_ROOT/lib-gcc5/libgtest.a
+
+########################################
+#GCC-6
+gcc-6-root: $GCC6_ROOT/bin
+gcc-6-cxx: g++-6
+gcc-6-cc: gcc-6
+gcc-6-boost: $BOOST_ROOT
+gcc-6-cxxflags: -march=native -std=c++14
+gcc-6-exe-ldflags: -Wl,-rpath=$GCC6_ROOT/lib64
+gcc-6-extlib: rt
+gcc-6-64-boost-lib: stage64-gcc6/lib
+gcc-6-64-asan-boost-lib: stage64-gcc6-asan/lib
+gcc-6-64-tsan-boost-lib: stage64-gcc6-tsan/lib
+gcc-6-gtest: $GTEST_ROOT
+gcc-6-64-gtest-lib: $GTEST_ROOT/lib-gcc6/libgtest.a
+
+########################################
+#GCC-7
+gcc-7-root: $GCC7_ROOT/bin
+gcc-7-cxx: g++-7
+gcc-7-cc: gcc-7
+gcc-7-boost: $BOOST_ROOT
+gcc-7-cxxflags: -march=native -std=c++1z
+gcc-7-exe-ldflags: -Wl,-rpath=$GCC7_ROOT/lib64
+gcc-7-extlib: rt
+gcc-7-64-boost-lib: stage64-gcc7/lib
+gcc-7-64-asan-boost-lib: stage64-gcc7-asan/lib
+gcc-7-64-tsan-boost-lib: stage64-gcc7-tsan/lib
+gcc-7-gtest: $GTEST_ROOT
+gcc-7-64-gtest-lib: $GTEST_ROOT/lib-gcc7/libgtest.a
+
+########################################
+#GCC-8
+gcc-8-root: $GCC8_ROOT/bin
+gcc-8-cxx: g++-8
+gcc-8-cc: gcc-8
+gcc-8-boost: $BOOST_ROOT
+gcc-8-cxxflags: -march=native -std=c++17 -Wmultistatement-macros
+gcc-8-exe-ldflags: -Wl,-rpath=$GCC8_ROOT/lib64
+gcc-8-extlib: rt
+gcc-8-path: $DEVTOOLSET6_BIN
+gcc-8-64-boost-lib: stage64-gcc7/lib
+gcc-8-64-asan-boost-lib: stage64-gcc7-asan/lib
+gcc-8-64-tsan-boost-lib: stage64-gcc7-tsan/lib
+gcc-8-gtest: $GTEST_ROOT
+gcc-8-64-gtest-lib: $GTEST_ROOT/lib-gcc7/libgtest.a
+
+########################################
+# clang-3.6
+clang-3.6-root: $CLANG36_ROOT/bin
+clang-3.6-ld-lib-path: $GCC5_ROOT/lib64
+clang-3.6-cxx: clang++
+clang-3.6-cc: clang
+clang-3.6-cxxflags: -Wdocumentation
+clang-3.6-exe-ldflags: -L$GCC5_ROOT/lib64 -latomic -Wl,-rpath=$GCC5_ROOT/lib64
+clang-3.6-extlib: rt
+clang-3.6-boost: $BOOST_ROOT
+clang-3.6-64-boost-lib: stage64-clang3.6/lib
+clang-3.6-gtest: $GTEST_ROOT
+clang-3.6-64-gtest-lib: $GTEST_ROOT/lib-clang3.6/libgtest.a
+
+########################################
+# clang-3.7
+clang-3.7-root: $CLANG37_ROOT/bin
+clang-3.7-ld-lib-path: $GCC6_ROOT/lib64
+clang-3.7-cxx: clang++
+clang-3.7-cc: clang
+clang-3.7-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.7-exe-ldflags: -L$CLANG37_ROOT/lib -Wl,-rpath=$CLANG37_ROOT/lib -lc++abi
+clang-3.7-extlib: rt
+clang-3.7-boost: $BOOST_ROOT
+clang-3.7-64-boost-lib: stage64-clang3.7/lib
+clang-3.7-gtest: $GTEST_ROOT
+clang-3.7-64-gtest-lib: $GTEST_ROOT/lib-clang3.7/libgtest.a
+clang-3.7-cmake-flags: -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1
+
+
+########################################
+# clang-3.8
+clang-3.8-root: $CLANG38_ROOT/bin
+clang-3.8-ld-lib-path: $GCC6_ROOT/lib64
+clang-3.8-cxx: clang++
+clang-3.8-cc: clang
+clang-3.8-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.8-exe-ldflags: -L$CLANG38_ROOT/lib -Wl,-rpath=$CLANG38_ROOT/lib
+clang-3.8-extlib: rt
+clang-3.8-boost: $BOOST_ROOT
+clang-3.8-64-boost-lib: stage64-clang3.8/lib
+clang-3.8-gtest: $GTEST_ROOT
+clang-3.8-64-gtest-lib: $GTEST_ROOT/lib-clang3.8/libgtest.a
+
+
+########################################
+# clang-3.9
+clang-3.9-root: $CLANG39_ROOT/bin
+clang-3.9-ld-lib-path: $GCC6_ROOT/lib64
+clang-3.9-cxx: clang++
+clang-3.9-cc: clang
+clang-3.9-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.9-exe-ldflags: -L$CLANG39_ROOT/lib -Wl,-rpath=$CLANG39_ROOT/lib
+clang-3.9-extlib: rt
+clang-3.9-boost: $BOOST_ROOT
+clang-3.9-64-boost-lib: stage64-clang3.9/lib
+clang-3.9-64-asan-boost-lib: stage64-clang3.9-asan/lib
+clang-3.9-64-tsan-boost-lib: stage64-clang3.9-tsan/lib
+clang-3.9-gtest: $GTEST_ROOT
+clang-3.9-64-gtest-lib: $GTEST_ROOT/lib-clang3.9/libgtest.a
+
+
+########################################
+# clang-4
+clang-4-root: $CLANG4_ROOT/bin
+clang-4-cxx: clang++
+clang-4-cc: clang
+clang-4-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++14
+clang-4-exe-ldflags: -L$CLANG4_ROOT/lib -Wl,-rpath=$CLANG4_ROOT/lib
+clang-4-extlib: rt
+clang-4-boost: $BOOST_ROOT
+clang-4-64-boost-lib: stage64-clang4/lib
+clang-4-64-asan-boost-lib: stage64-clang4-asan/lib
+clang-4-64-tsan-boost-lib: stage64-clang4-tsan/lib
+clang-4-gtest: $GTEST_ROOT
+clang-4-64-gtest-lib: $GTEST_ROOT/lib-clang4/libgtest.a
+
+
+########################################
+# clang-5
+clang-5-root: $CLANG5_ROOT/bin
+clang-5-cxx: clang++
+clang-5-cc: clang
+clang-5-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++1z
+clang-5-exe-ldflags: -L$CLANG5_ROOT/lib -Wl,-rpath=$CLANG5_ROOT/lib
+clang-5-extlib: rt
+clang-5-path: $DEVTOOLSET6_BIN
+clang-5-boost: $LIB_ROOT/boost_1_65_1
+clang-5-64-boost-lib: stage64-clang5-std17/lib
+clang-5-64-asan-boost-lib: stage64-clang5-asan/lib
+clang-5-64-tsan-boost-lib: stage64-clang5-tsan/lib
+clang-5-gtest: $GTEST_ROOT
+clang-5-64-gtest-lib: $GTEST_ROOT/lib-clang5/libgtest.a
+
+
+########################################
+# clang-6
+clang-6-root: $CLANG6_ROOT/bin
+clang-6-cxx: clang++
+clang-6-cc: clang
+clang-6-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++17
+clang-6-exe-ldflags: -L$CLANG6_ROOT/lib -Wl,-rpath=$CLANG6_ROOT/lib
+clang-6-extlib: rt
+clang-6-path: $DEVTOOLSET6_BIN
+clang-6-boost: $LIB_ROOT/boost_1_65_1
+clang-6-64-boost-lib: stage64-clang6-std17/lib
+clang-6-64-asan-boost-lib: stage64-clang6-asan/lib
+clang-6-64-tsan-boost-lib: stage64-clang6-tsan/lib
+clang-6-gtest: $GTEST_ROOT
+clang-6-64-gtest-lib: $GTEST_ROOT/lib-clang6/libgtest.a
+
+
+########################################
+# clang-7
+clang-7-root: $CLANG6_ROOT/bin
+clang-7-cxx: clang++
+clang-7-cc: clang
+clang-7-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++17
+clang-7-exe-ldflags: -fuse-ld=lld -L$CLANG7_ROOT/lib -Wl,-rpath=$CLANG7_ROOT/lib
+clang-7-extlib: rt
+clang-7-path: $DEVTOOLSET6_BIN
+clang-7-boost: $LIB_ROOT/boost_1_65_1
+clang-7-64-boost-lib: stage64-clang7-std17/lib
+clang-7-64-asan-boost-lib: stage64-clang7-asan/lib
+clang-7-64-tsan-boost-lib: stage64-clang7-tsan/lib
+clang-7-gtest: $GTEST_ROOT
+clang-7-64-gtest-lib: $GTEST_ROOT/lib-clang6/libgtest.a
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extern/libcds/build/CI/VASEx-CI-2/ci-build b/extern/libcds/build/CI/VASEx-CI-2/ci-build
new file mode 100644
index 0000000000..0bbe60bb7c
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI-2/ci-build
@@ -0,0 +1,88 @@
+#! /bin/bash
+
+# Useful envvars:
+# CI_SCRIPT_PATH - path where to find scripts
+# TOOLSET - toolset: x64-gcc-5, x64-clang-3.9 and so on
+# BUILD_TYPE - build type: 'dbg', 'rel', 'asan', 'tsan'
+# WORKSPACE - path where to build
+
+env|sort
+
+case "$TOOLSET" in
+ "x64-gcc-4.8")
+ echo "GCC-4.8 '$BUILD_TYPE', toolset root: $GCC48_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-4.8-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-gcc-4.9")
+ echo "GCC-4.9 '$BUILD_TYPE', toolset root: $GCC49_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-4.9-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-gcc-5")
+ echo "GCC-5 '$BUILD_TYPE', toolset root: $GCC5_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-5-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-gcc-6")
+ echo "GCC-6 '$BUILD_TYPE', toolset root: $GCC6_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-6-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-gcc-7")
+ echo "GCC-7 '$BUILD_TYPE', toolset root: $GCC7_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-7-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-gcc-8")
+ echo "GCC-8 '$BUILD_TYPE', toolset root: $GCC8_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-8-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-3.6")
+ echo "clang-3.6 '$BUILD_TYPE', toolset root: $CLANG36_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.6-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-3.7")
+ echo "clang-3.7 '$BUILD_TYPE', toolset root: $CLANG37_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.7-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-3.8")
+ echo "clang-3.8 '$BUILD_TYPE', toolset root: $CLANG38_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.8-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-3.9")
+ echo "clang-3.9 '$BUILD_TYPE', toolset root: $CLANG39_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.9-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-4")
+ echo "clang-4 '$BUILD_TYPE', toolset root: $CLANG4_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-4-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-5")
+ echo "clang-5 '$BUILD_TYPE', toolset root: $CLANG5_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-5-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-6")
+ echo "clang-6 '$BUILD_TYPE', toolset root: $CLANG6_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-6-64 $*
+ EXIT_CODE=$?
+ ;;
+ "x64-clang-7")
+ echo "clang-7 '$BUILD_TYPE', toolset root: $CLANG7_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-7-64 $*
+ EXIT_CODE=$?
+ ;;
+ * )
+ echo "Undefined toolset '$TOOLSET'"
+ exit 1
+ ;;
+esac
+
+exit $EXIT_CODE
diff --git a/extern/libcds/build/CI/VASEx-CI-2/ci-env b/extern/libcds/build/CI/VASEx-CI-2/ci-env
new file mode 100644
index 0000000000..827179a359
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI-2/ci-env
@@ -0,0 +1,38 @@
+#CMAKE_2_8_12=/home/libcds-ci/bin/cmake/cmake-2.8.12/bin
+CMAKE_3_6_2=/home/libcds-ci/bin/cmake-3.6/bin
+CMAKE3=$CMAKE_3_6_2
+
+PATH=$CMAKE3:$PATH:$HOME/.local/bin:$HOME/bin
+
+DEVTOOLSET6_BIN=/opt/rh/devtoolset-6/root/usr/bin
+
+TOOLSET_ROOT=$HOME/bin
+
+GCC48_ROOT=$TOOLSET_ROOT/gcc-4.8
+GCC49_ROOT=$TOOLSET_ROOT/gcc-4.9
+GCC5_ROOT=$TOOLSET_ROOT/gcc-5
+GCC6_ROOT=$TOOLSET_ROOT/gcc-6
+GCC7_ROOT=$TOOLSET_ROOT/gcc-7
+GCC8_ROOT=$TOOLSET_ROOT/gcc-8
+
+CLANG36_ROOT=$TOOLSET_ROOT/clang-3.6
+CLANG37_ROOT=$TOOLSET_ROOT/clang-3.7
+CLANG38_ROOT=$TOOLSET_ROOT/clang-3.8
+CLANG39_ROOT=$TOOLSET_ROOT/clang-3.9
+CLANG4_ROOT=$TOOLSET_ROOT/clang-4
+CLANG5_ROOT=$TOOLSET_ROOT/clang-5
+CLANG6_ROOT=$TOOLSET_ROOT/clang-6
+CLANG7_ROOT=$TOOLSET_ROOT/clang-7
+
+CLANG_STDLIB="-stdlib=libc++"
+CLANG37_CXXFLAGS=$CLANG_STDLIB
+CLANG38_CXXFLAGS=$CLANG_STDLIB
+CLANG39_CXXFLAGS=$CLANG_STDLIB
+CLANG4_CXXFLAGS=$CLANG_STDLIB
+CLANG5_CXXFLAGS=$CLANG_STDLIB
+CLANG6_CXXFLAGS=$CLANG_STDLIB
+CLANG7_CXXFLAGS="$CLANG_STDLIB -fuse-ld=lld"
+
+LIB_ROOT=$HOME/lib
+BOOST_ROOT=$LIB_ROOT/boost
+GTEST_ROOT=$LIB_ROOT/gtest
diff --git a/extern/libcds/build/CI/VASEx-CI/cds-libs b/extern/libcds/build/CI/VASEx-CI/cds-libs
new file mode 100644
index 0000000000..ef9c98c69e
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI/cds-libs
@@ -0,0 +1,195 @@
+#########################################
+# Generic parameters
+
+workspace: $WORKSPACE
+libcds-source: source
+make-job: 10
+gtest-include: $GTEST_ROOT/googletest/include
+
+#########################################
+#GCC-4.8
+gcc-4.8-root: $GCC48_ROOT/bin
+gcc-4.8-cxx: g++-4.8
+gcc-4.8-cc: gcc-4.8
+gcc-4.8-exe-ldflags: -L$GCC48_ROOT/lib64 -Wl,-rpath=$GCC48_ROOT/lib64
+gcc-4.8-boost: $BOOST_ROOT
+gcc-4.8-64-boost-lib: stage64-gcc4.8/lib
+gcc-4.8-gtest: $GTEST_ROOT
+gcc-4.8-64-gtest-lib: $GTEST_ROOT/lib-gcc4.8/libgtest.a
+
+
+########################################
+#GCC-4.9
+gcc-4.9-root: $GCC49_ROOT/bin
+gcc-4.9-cxx: g++-4.9
+gcc-4.9-cc: gcc-4.9
+gcc-4.9-exe-ldflags: -Wl,-rpath=$GCC49_ROOT/lib64
+gcc-4.9-boost: $BOOST_ROOT
+gcc-4.9-64-boost-lib: stage64-gcc4.9/lib
+gcc-4.9-gtest: $GTEST_ROOT
+gcc-4.9-64-gtest-lib: $GTEST_ROOT/lib-gcc4.9/libgtest.a
+
+########################################
+#GCC-5
+gcc-5-root: $GCC5_ROOT/bin
+gcc-5-cxx: g++-5
+gcc-5-cc: gcc-5
+gcc-5-boost: $BOOST_ROOT
+gcc-5-exe-ldflags: -Wl,-rpath=$GCC5_ROOT/lib64
+gcc-5-64-boost-lib: stage64-gcc5/lib
+gcc-5-64-asan-boost-lib: stage64-gcc5-asan/lib
+gcc-5-64-tsan-boost-lib: stage64-gcc5-tsan/lib
+gcc-5-gtest: $GTEST_ROOT
+gcc-5-64-gtest-lib: $GTEST_ROOT/lib-gcc5/libgtest.a
+
+########################################
+#GCC-6
+gcc-6-root: $GCC6_ROOT/bin
+gcc-6-cxx: g++-6
+gcc-6-cc: gcc-6
+gcc-6-boost: $BOOST_ROOT
+gcc-6-cxxflags: -march=native -std=c++14
+gcc-6-exe-ldflags: -Wl,-rpath=$GCC6_ROOT/lib64
+gcc-6-64-boost-lib: stage64-gcc6/lib
+gcc-6-64-asan-boost-lib: stage64-gcc6-asan/lib
+gcc-6-64-tsan-boost-lib: stage64-gcc6-tsan/lib
+gcc-6-gtest: $GTEST_ROOT
+gcc-6-64-gtest-lib: $GTEST_ROOT/lib-gcc6/libgtest.a
+
+
+########################################
+#GCC-7
+gcc-7-root: $GCC7_ROOT/bin
+gcc-7-cxx: g++-7
+gcc-7-cc: gcc-7
+gcc-7-boost: $BOOST_ROOT
+gcc-7-cxxflags: -march=native -std=c++1z
+gcc-7-exe-ldflags: -Wl,-rpath=$GCC7_ROOT/lib64
+gcc-7-64-boost-lib: stage64-gcc7/lib
+gcc-7-64-asan-boost-lib: stage64-gcc7-asan/lib
+gcc-7-64-tsan-boost-lib: stage64-gcc7-tsan/lib
+gcc-7-gtest: $GTEST_ROOT
+gcc-7-64-gtest-lib: $GTEST_ROOT/lib-gcc7/libgtest.a
+
+########################################
+#GCC-8
+gcc-8-root: $GCC8_ROOT/bin
+gcc-8-cxx: g++-8
+gcc-8-cc: gcc-8
+gcc-8-boost: $BOOST_ROOT
+gcc-8-cxxflags: -march=native -std=c++17 -Wmultistatement-macros
+gcc-8-exe-ldflags: -Wl,-rpath=$GCC8_ROOT/lib64
+gcc-8-extlib: rt
+gcc-8-64-boost-lib: stage64-gcc7/lib
+gcc-8-64-asan-boost-lib: stage64-gcc7-asan/lib
+gcc-8-64-tsan-boost-lib: stage64-gcc7-tsan/lib
+gcc-8-gtest: $GTEST_ROOT
+gcc-8-64-gtest-lib: $GTEST_ROOT/lib-gcc7/libgtest.a
+
+
+########################################
+# clang-3.6
+clang-3.6-root: $CLANG36_ROOT/bin
+clang-3.6-ld-lib-path: $GCC6_ROOT/lib64
+clang-3.6-cxx: clang++
+clang-3.6-cc: clang
+clang-3.6-cxxflags: -Wdocumentation
+clang-3.6-exe-ldflags: -L$GCC5_ROOT/lib64 -latomic -Wl,-rpath=$GCC5_ROOT/lib64
+clang-3.6-boost: $BOOST_ROOT
+clang-3.6-64-boost-lib: stage64-clang3.6/lib
+clang-3.6-gtest: $GTEST_ROOT
+clang-3.6-64-gtest-lib: $GTEST_ROOT/lib-clang3.6/libgtest.a
+
+########################################
+# clang-3.7
+clang-3.7-root: $CLANG37_ROOT/bin
+clang-3.7-cxx: clang++
+clang-3.7-cc: clang
+clang-3.7-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.7-exe-ldflags: -L$CLANG37_ROOT/lib -Wl,-rpath=$CLANG37_ROOT/lib -lc++abi
+clang-3.7-boost: $BOOST_ROOT
+clang-3.7-64-boost-lib: stage64-clang3.7/lib
+clang-3.7-gtest: $GTEST_ROOT
+clang-3.7-64-gtest-lib: $GTEST_ROOT/lib-clang3.7/libgtest.a
+clang-3.7-cmake-flags: -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER_WORKS=1
+
+########################################
+# clang-3.8
+clang-3.8-root: $CLANG38_ROOT/bin
+clang-3.8-cxx: clang++
+clang-3.8-cc: clang
+clang-3.8-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.8-exe-ldflags: -L$CLANG38_ROOT/lib -Wl,-rpath=$CLANG38_ROOT/lib
+clang-3.8-boost: $BOOST_ROOT
+clang-3.8-64-boost-lib: stage64-clang3.8/lib
+clang-3.8-gtest: $GTEST_ROOT
+clang-3.8-64-gtest-lib: $GTEST_ROOT/lib-clang3.8/libgtest.a
+
+
+########################################
+# clang-3.9
+clang-3.9-root: $CLANG39_ROOT/bin
+clang-3.9-cxx: clang++
+clang-3.9-cc: clang
+clang-3.9-cxxflags: -stdlib=libc++ -Wdocumentation
+clang-3.9-exe-ldflags: -L$CLANG39_ROOT/lib -Wl,-rpath=$CLANG39_ROOT/lib
+clang-3.9-boost: $BOOST_ROOT
+clang-3.9-64-boost-lib: stage64-clang3.9/lib
+clang-3.9-64-asan-boost-lib: stage64-clang3.9-asan/lib
+clang-3.9-64-tsan-boost-lib: stage64-clang3.9-tsan/lib
+clang-3.9-gtest: $GTEST_ROOT
+clang-3.9-64-gtest-lib: $GTEST_ROOT/lib-clang3.9/libgtest.a
+
+
+########################################
+# clang-4
+clang-4-root: $CLANG4_ROOT/bin
+clang-4-cxx: clang++
+clang-4-cc: clang
+clang-4-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++14
+clang-4-exe-ldflags: -L$CLANG4_ROOT/lib -Wl,-rpath=$CLANG4_ROOT/lib
+clang-4-boost: $BOOST_ROOT
+clang-4-64-boost-lib: stage64-clang4/lib
+clang-4-64-asan-boost-lib: stage64-clang4-asan/lib
+clang-4-64-tsan-boost-lib: stage64-clang4-tsan/lib
+clang-4-gtest: $GTEST_ROOT
+clang-4-64-gtest-lib: $GTEST_ROOT/lib-clang4/libgtest.a
+
+########################################
+# clang-5
+clang-5-root: $CLANG5_ROOT/bin
+clang-5-cxx: clang++
+clang-5-cc: clang
+clang-5-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++1z
+clang-5-exe-ldflags: -L$CLANG5_ROOT/lib -Wl,-rpath=$CLANG5_ROOT/lib
+clang-5-boost: $LIB_ROOT/boost_1_65_1
+clang-5-64-boost-lib: stage64-clang5-std17/lib
+clang-5-64-asan-boost-lib: stage64-clang5-asan/lib
+clang-5-64-tsan-boost-lib: stage64-clang5-tsan/lib
+clang-5-gtest: $GTEST_ROOT
+clang-5-64-gtest-lib: $GTEST_ROOT/lib-clang5/libgtest.a
+
+########################################
+# clang-6
+clang-6-root: $CLANG6_ROOT/bin
+clang-6-cxx: clang++
+clang-6-cc: clang
+clang-6-cxxflags: -stdlib=libc++ -Wdocumentation -std=c++17
+clang-6-exe-ldflags: -L$CLANG6_ROOT/lib -Wl,-rpath=$CLANG6_ROOT/lib
+clang-6-boost: $LIB_ROOT/boost_1_65_1
+clang-6-64-boost-lib: stage64-clang6-std17/lib
+clang-6-64-asan-boost-lib: stage64-clang6-asan/lib
+clang-6-64-tsan-boost-lib: stage64-clang6-tsan/lib
+clang-6-gtest: $GTEST_ROOT
+clang-6-64-gtest-lib: $GTEST_ROOT/lib-clang6/libgtest.a
+
+
+
+
+
+
+
+
+
+
+
diff --git a/extern/libcds/build/CI/VASEx-CI/ci-build b/extern/libcds/build/CI/VASEx-CI/ci-build
new file mode 100644
index 0000000000..876ae27c29
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI/ci-build
@@ -0,0 +1,81 @@
+#! /bin/bash
+
+# Useful envvars:
+# CI_SCRIPT_PATH - path where to find scripts
+# TOOLSET - toolset: x64-gcc-5, x64-clang-3.9 and so on
+# BUILD_TYPE - build type: 'dbg', 'rel', 'asan', 'tsan'
+# WORKSPACE - path where to build
+
+env|sort
+
+case "$TOOLSET" in
+ "x64-gcc-4.8")
+ echo "GCC-4.8 '$BUILD_TYPE', toolset root: $GCC48_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-4.8-64 $*
+ exit $?
+ ;;
+ "x64-gcc-4.9")
+ echo "GCC-4.9 '$BUILD_TYPE', toolset root: $GCC49_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-4.9-64 $*
+ exit $?
+ ;;
+ "x64-gcc-5")
+ echo "GCC-5 '$BUILD_TYPE', toolset root: $GCC5_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-5-64 $*
+ exit $?
+ ;;
+ "x64-gcc-6")
+ echo "GCC-6 '$BUILD_TYPE', toolset root: $GCC6_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-6-64 $*
+ exit $?
+ ;;
+ "x64-gcc-7")
+ echo "GCC-7 '$BUILD_TYPE', toolset root: $GCC7_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-7-64 $*
+ exit $?
+ ;;
+ "x64-gcc-8")
+ echo "GCC-8 '$BUILD_TYPE', toolset root: $GCC8_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-gcc-8-64 $*
+ exit $?
+ ;;
+ "x64-clang-3.6")
+ echo "clang-3.6 '$BUILD_TYPE', toolset root: $CLANG36_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.6-64 $*
+ exit $?
+ ;;
+ "x64-clang-3.7")
+ echo "clang-3.7 '$BUILD_TYPE', toolset root: $CLANG37_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.7-64 $*
+ exit $?
+ ;;
+ "x64-clang-3.8")
+ echo "clang-3.8 '$BUILD_TYPE', toolset root: $CLANG38_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.8-64 $*
+ exit $?
+ ;;
+ "x64-clang-3.9")
+ echo "clang-3.9 '$BUILD_TYPE', toolset root: $CLANG39_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-3.9-64 $*
+ exit $?
+ ;;
+ "x64-clang-4")
+ echo "clang-4 '$BUILD_TYPE', toolset root: $CLANG4_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-4-64 $*
+ exit $?
+ ;;
+ "x64-clang-5")
+ echo "clang-5 '$BUILD_TYPE', toolset root: $CLANG5_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-5-64 $*
+ exit $?
+ ;;
+ "x64-clang-6")
+ echo "clang-6 '$BUILD_TYPE', toolset root: $CLANG6_ROOT"
+ $CI_SCRIPT_PATH/ci-script/cds-$BUILD_TYPE-clang-6-64 $*
+ exit $?
+ ;;
+ * )
+ echo "Undefined toolset '$TOOLSET'"
+ exit 1
+ ;;
+esac
diff --git a/extern/libcds/build/CI/VASEx-CI/ci-env b/extern/libcds/build/CI/VASEx-CI/ci-env
new file mode 100644
index 0000000000..1bd3559806
--- /dev/null
+++ b/extern/libcds/build/CI/VASEx-CI/ci-env
@@ -0,0 +1,35 @@
+CMAKE_2_8_12=/home/libcds-ci/bin/cmake/cmake-2.8.12/bin
+CMAKE_3_6_2=/home/libcds-ci/bin/cmake/cmake-3.6.2/bin
+CMAKE3=$CMAKE_3_6_2
+
+PATH=$CMAKE3:$PATH:$HOME/.local/bin:$HOME/bin
+
+TOOLSET_ROOT=$HOME/bin
+
+GCC48_ROOT=$TOOLSET_ROOT/gcc-4.8
+GCC49_ROOT=$TOOLSET_ROOT/gcc-4.9
+GCC5_ROOT=$TOOLSET_ROOT/gcc-5
+GCC6_ROOT=$TOOLSET_ROOT/gcc-6
+GCC7_ROOT=$TOOLSET_ROOT/gcc-7
+GCC8_ROOT=$TOOLSET_ROOT/gcc-8
+
+CLANG35_ROOT=$TOOLSET_ROOT/clang-3.5
+CLANG36_ROOT=$TOOLSET_ROOT/clang-3.6
+CLANG37_ROOT=$TOOLSET_ROOT/clang-3.7
+CLANG38_ROOT=$TOOLSET_ROOT/clang-3.8
+CLANG39_ROOT=$TOOLSET_ROOT/clang-3.9
+CLANG4_ROOT=$TOOLSET_ROOT/clang-4
+CLANG5_ROOT=$TOOLSET_ROOT/clang-5
+CLANG6_ROOT=$TOOLSET_ROOT/clang-6
+
+CLANG_STDLIB="-stdlib=libc++"
+CLANG37_CXXFLAGS=$CLANG_STDLIB
+CLANG38_CXXFLAGS=$CLANG_STDLIB
+CLANG39_CXXFLAGS=$CLANG_STDLIB
+CLANG4_CXXFLAGS=$CLANG_STDLIB
+CLANG5_CXXFLAGS=$CLANG_STDLIB
+CLANG6_CXXFLAGS=$CLANG_STDLIB
+
+LIB_ROOT=$HOME/lib
+BOOST_ROOT=$LIB_ROOT/boost
+GTEST_ROOT=$LIB_ROOT/gtest
diff --git a/extern/libcds/build/CI/cmake-gen b/extern/libcds/build/CI/cmake-gen
new file mode 100644
index 0000000000..015bfd3906
--- /dev/null
+++ b/extern/libcds/build/CI/cmake-gen
@@ -0,0 +1,113 @@
+#! /usr/bin/perl
+
+my $compiler=shift;
+my $bitness =shift;
+my $build =shift;
+$build="rel" unless $build;
+
+my $cmake_build="RELEASE";
+$cmake_build="DEBUG" if $build eq 'dbg';
+
+my $cds_libs="cds-libs";
+
+# get generic props
+my $workspace=get_gen_prop("workspace") || "$HOME";
+my $cds_source=get_gen_prop("libcds-source") || "../libcds";
+my $make_jobs=get_gen_prop("make-job") || 2;
+
+# get compiler-specific props
+my $comp_root=get_prop("root");
+my $boost=get_prop( "boost" );
+my $boost_libs=get_prop( "boost-lib" );
+my $gtest=get_prop("gtest");
+my $gtest_lib=get_prop( "gtest-lib");
+my $gtest_inc=get_prop("gtest-include") || get_gen_prop("gtest-include");
+my $cxx=get_prop("cxx") or $compiler;
+my $cc=get_prop("cc") or $compiler;
+my $cxxflags=get_prop("cxxflags");
+my $ldflags=get_prop("ldflags");
+my $cmake_exe_ldflags=get_prop("exe-ldflags");
+my $ext_lib=get_prop("extlib");
+my $ld_lib_path=get_prop("ld-lib-path");
+my $sys_path=get_prop("path");
+my $cmake_flags=get_prop("cmake-flags");
+
+my $filename="cds-$build-$compiler-$bitness";
+open( my $out, ">", $filename ) or die "Cannot open cds-$build-$compiler-$bitness";
+
+print $out "#! /bin/sh\n\n";
+print $out "root=$workspace\n";
+print $out "CDS_SOURCE=\$root/$cds_source\n";
+print $out "OBJ_ROOT=\$root/obj\n";
+print $out "BIN_ROOT=\$root/bin\n";
+print $out "GTEST_ROOT=$gtest\n" if $gtest;
+print $out "export PATH=$sys_path:\$PATH\n" if $sys_path;
+print $out "\n";
+print $out "rm -fr \$OBJ_ROOT\n";
+print $out "rm -fr \$BIN_ROOT\n";
+print $out "mkdir -p \$OBJ_ROOT\n";
+print $out "#cp -f run-ctest-rel \$OBJ_ROOT/run-ctest\n" if $build eq 'rel';
+print $out "#cp -f run-ctest-dbg \$OBJ_ROOT/run-ctest\n" unless $build eq 'rel';
+print $out "cd \$OBJ_ROOT\n";
+print $out "\n";
+print $out "LD_LIBRARY_PATH=$ld_lib_path:\$LD_LIBRARY_PATH \\\n" if $ld_lib_path;
+print $out "LDFLAGS=\"$ldflags\" \\\n" if $ldflags;
+print $out "cmake -G \"Unix Makefiles\" \\\n";
+print $out " -DCMAKE_BUILD_TYPE=$cmake_build \\\n";
+print $out " -DCMAKE_C_COMPILER=$comp_root/$cc \\\n";
+print $out " -DCMAKE_CXX_COMPILER=$comp_root/$cxx \\\n";
+print $out " -DCMAKE_CXX_FLAGS=\"$cxxflags\" \\\n" if $cxxflags;
+print $out " -DCMAKE_EXE_LINKER_FLAGS=\"$cmake_exe_ldflags\" \\\n" if $cmake_exe_ldflags;
+print $out " -DCDS_BIN_DIR=\$BIN_ROOT \\\n";
+print $out " -DWITH_TESTS=ON \\\n";
+print $out " -DWITH_ASAN=ON \\\n" if $build eq 'asan';
+print $out " -DWITH_TSAN=ON \\\n" if $build eq 'tsan';
+print $out " -DBOOST_ROOT=$boost \\\n";
+print $out " -DBOOST_LIBRARYDIR=$boost/$boost_libs \\\n" if $boost_libs;
+print $out " -DGTEST_INCLUDE_DIRS=$gtest_inc \\\n" if $gtest_inc;
+print $out " -DGTEST_LIBRARIES=$gtest_lib \\\n" if $gtest_lib;
+print $out " -DEXTERNAL_SYSTEM_LIBS=\"$ext_lib\" \\\n" if $ext_lib;
+print $out " $cmake_flags \\\n" if $cmake_flags;
+print $out " \$CDS_SOURCE && \\\n";
+print $out "make -j $make_jobs \$* \n";
+
+close $out;
+chmod 0755, $filename;
+
+sub get_prop($@)
+{
+ my $what=shift;
+ my $key="$compiler-$bitness-$build-$what:";
+
+ my $grep = `grep -P $key $cds_libs`;
+ if ( $grep ) {
+ my @ret = $grep =~ /^$key\s+(\S.*\S*)\s+/;
+ return $ret[0] if @ret;
+ }
+
+ $key = "$compiler-$bitness-$what:";
+ my $grep = `grep -P $key $cds_libs`;
+ if ( $grep ) {
+ my @ret = $grep =~ /^$key\s+(\S.*\S*)\s+/;
+ return $ret[0] if @ret;
+ }
+
+ $key = "$compiler-$what:";
+ my $grep = `grep -P $key $cds_libs`;
+ if ( $grep ) {
+ my @ret = $grep =~ /^$key\s+(\S.*\S*)\s+/;
+ return $ret[0] if @ret;
+ }
+}
+
+sub get_gen_prop($@)
+{
+ my $key=shift;
+ $key = "$key:";
+
+ my $grep = `grep -P $key $cds_libs`;
+ if ( $grep ) {
+ my @ret = $grep =~ /^$key\s+(\S.*\S*)\s+/;
+ return $ret[0] if @ret;
+ }
+}
\ No newline at end of file
diff --git a/extern/libcds/build/CI/gen-all b/extern/libcds/build/CI/gen-all
new file mode 100644
index 0000000000..2c89feaae6
--- /dev/null
+++ b/extern/libcds/build/CI/gen-all
@@ -0,0 +1,48 @@
+#! /bin/sh
+
+./cmake-gen gcc-4.8 64 dbg
+./cmake-gen gcc-4.8 64 rel
+./cmake-gen gcc-4.9 64 dbg
+./cmake-gen gcc-4.9 64 rel
+./cmake-gen gcc-5 64 dbg
+./cmake-gen gcc-5 64 rel
+./cmake-gen gcc-5 64 tsan
+./cmake-gen gcc-5 64 asan
+./cmake-gen gcc-6 64 dbg
+./cmake-gen gcc-6 64 rel
+./cmake-gen gcc-6 64 tsan
+./cmake-gen gcc-6 64 asan
+./cmake-gen gcc-7 64 dbg
+./cmake-gen gcc-7 64 rel
+./cmake-gen gcc-7 64 tsan
+./cmake-gen gcc-7 64 asan
+./cmake-gen gcc-8 64 dbg
+./cmake-gen gcc-8 64 rel
+./cmake-gen gcc-8 64 tsan
+./cmake-gen gcc-8 64 asan
+./cmake-gen clang-3.6 64 dbg
+./cmake-gen clang-3.6 64 rel
+./cmake-gen clang-3.7 64 dbg
+./cmake-gen clang-3.7 64 rel
+./cmake-gen clang-3.8 64 dbg
+./cmake-gen clang-3.8 64 rel
+./cmake-gen clang-3.9 64 dbg
+./cmake-gen clang-3.9 64 rel
+./cmake-gen clang-3.9 64 asan
+./cmake-gen clang-3.9 64 tsan
+./cmake-gen clang-4 64 dbg
+./cmake-gen clang-4 64 rel
+./cmake-gen clang-4 64 asan
+./cmake-gen clang-4 64 tsan
+./cmake-gen clang-5 64 dbg
+./cmake-gen clang-5 64 rel
+./cmake-gen clang-5 64 asan
+./cmake-gen clang-5 64 tsan
+./cmake-gen clang-6 64 dbg
+./cmake-gen clang-6 64 rel
+./cmake-gen clang-6 64 asan
+./cmake-gen clang-6 64 tsan
+./cmake-gen clang-7 64 dbg
+./cmake-gen clang-7 64 rel
+./cmake-gen clang-7 64 asan
+./cmake-gen clang-7 64 tsan
\ No newline at end of file
diff --git a/extern/libcds/build/CI/travis-ci/install.sh b/extern/libcds/build/CI/travis-ci/install.sh
new file mode 100644
index 0000000000..4b6b6648f2
--- /dev/null
+++ b/extern/libcds/build/CI/travis-ci/install.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ brew update || brew update
+ brew outdated pyenv || brew upgrade pyenv
+ brew install pyenv-virtualenv
+ brew install cmake || true
+
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+
+ pyenv install 2.7.10
+ pyenv virtualenv 2.7.10 conan
+ pyenv rehash
+ pyenv activate conan
+
+ pip install conan --upgrade
+ pip install conan_package_tools
+
+ conan user
+ exit 0
+fi
+
+pip install --user conan --upgrade
+pip install --user conan_package_tools
+
+conan user
diff --git a/extern/libcds/build/CI/travis-ci/run.sh b/extern/libcds/build/CI/travis-ci/run.sh
new file mode 100644
index 0000000000..1f5636c7f1
--- /dev/null
+++ b/extern/libcds/build/CI/travis-ci/run.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+set -x
+
+CONAN_INSTALL_FLAGS="-s compiler.libcxx=libstdc++11"
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ if which pyenv > /dev/null; then
+ eval "$(pyenv init -)"
+ fi
+ pyenv activate conan
+ CONAN_INSTALL_FLAGS=""
+fi
+
+#export CXX=$CXX_COMPILER
+#export CC=$C_COMPILER
+mkdir build-test && cd build-test
+conan install --build $CONAN_INSTALL_FLAGS -s build_type=$BUILD_TYPE ..
+cmake -DCMAKE_PREFIX_PATH="$TRAVIS_BUILD_DIR/build-test/deps" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_EXE_LINKER_FLAGS=$LINKER_FLAGS -DWITH_TESTS=ON ..
+cmake --build . -- -j2 $TARGET
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+ export DYLD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/build-test/deps/lib
+fi
+ctest -VV -R $TARGET
diff --git a/extern/libcds/build/cmake/TargetArch.cmake b/extern/libcds/build/cmake/TargetArch.cmake
new file mode 100644
index 0000000000..026eace076
--- /dev/null
+++ b/extern/libcds/build/cmake/TargetArch.cmake
@@ -0,0 +1,141 @@
+# Source: https://github.com/axr/solar-cmake
+# Based on the Qt 5 processor detection code, so should be very accurate
+# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
+# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
+
+# Regarding POWER/PowerPC, just as is noted in the Qt source,
+# "There are many more known variants/revisions that we do not handle/detect."
+
+set(archdetect_c_code "
+#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
+ #if defined(__ARM_ARCH_7__) \\
+ || defined(__ARM_ARCH_7A__) \\
+ || defined(__ARM_ARCH_7R__) \\
+ || defined(__ARM_ARCH_7M__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
+ #error cmake_ARCH armv7
+ #elif defined(__ARM_ARCH_6__) \\
+ || defined(__ARM_ARCH_6J__) \\
+ || defined(__ARM_ARCH_6T2__) \\
+ || defined(__ARM_ARCH_6Z__) \\
+ || defined(__ARM_ARCH_6K__) \\
+ || defined(__ARM_ARCH_6ZK__) \\
+ || defined(__ARM_ARCH_6M__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
+ #error cmake_ARCH armv6
+ #elif defined(__ARM_ARCH_5TEJ__) \\
+ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
+ #error cmake_ARCH armv5
+ #else
+ #error cmake_ARCH arm
+ #endif
+#elif defined(__aarch64__)
+ #if defined(__ARM_ARCH) && __ARM_ARCH == 8
+ #error cmake_ARCH armv8
+ #else
+ #error cmake_ARCH arm64
+ #endif
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ #error cmake_ARCH i386
+#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
+ #error cmake_ARCH x86_64
+#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+ #error cmake_ARCH ia64
+#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
+ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
+ || defined(_M_MPPC) || defined(_M_PPC)
+ #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
+ #error cmake_ARCH ppc64
+ #else
+ #error cmake_ARCH ppc
+ #endif
+#endif
+
+#error cmake_ARCH unknown
+")
+
+# Set ppc_support to TRUE before including this file or ppc and ppc64
+# will be treated as invalid architectures since they are no longer supported by Apple
+
+function(target_architecture output_var)
+ if(APPLE AND CMAKE_OSX_ARCHITECTURES)
+ # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
+ # First let's normalize the order of the values
+
+ # Note that it's not possible to compile PowerPC applications if you are using
+ # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
+ # disable it by default
+ # See this page for more information:
+ # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
+
+ # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
+ # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
+
+ foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
+ if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
+ set(osx_arch_ppc TRUE)
+ elseif("${osx_arch}" STREQUAL "i386")
+ set(osx_arch_i386 TRUE)
+ elseif("${osx_arch}" STREQUAL "x86_64")
+ set(osx_arch_x86_64 TRUE)
+ elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
+ set(osx_arch_ppc64 TRUE)
+ else()
+ message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
+ endif()
+ endforeach()
+
+ # Now add all the architectures in our normalized order
+ if(osx_arch_ppc)
+ list(APPEND ARCH ppc)
+ endif()
+
+ if(osx_arch_i386)
+ list(APPEND ARCH i386)
+ endif()
+
+ if(osx_arch_x86_64)
+ list(APPEND ARCH x86_64)
+ endif()
+
+ if(osx_arch_ppc64)
+ list(APPEND ARCH ppc64)
+ endif()
+ else()
+ file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
+
+ enable_language(C)
+
+ # Detect the architecture in a rather creative way...
+ # This compiles a small C program which is a series of ifdefs that selects a
+ # particular #error preprocessor directive whose message string contains the
+ # target architecture. The program will always fail to compile (both because
+ # file is not a valid C program, and obviously because of the presence of the
+ # #error preprocessor directives... but by exploiting the preprocessor in this
+ # way, we can detect the correct target architecture even when cross-compiling,
+ # since the program itself never needs to be run (only the compiler/preprocessor)
+ try_run(
+ run_result_unused
+ compile_result_unused
+ "${CMAKE_BINARY_DIR}"
+ "${CMAKE_BINARY_DIR}/arch.c"
+ COMPILE_OUTPUT_VARIABLE ARCH
+ CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
+ )
+
+ # Parse the architecture name from the compiler output
+ string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
+
+ # Get rid of the value marker leaving just the architecture name
+ string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
+
+ # If we are compiling with an unknown architecture this variable should
+ # already be set to "unknown" but in the case that it's empty (i.e. due
+ # to a typo in the code), then set it to unknown
+ if (NOT ARCH)
+ set(ARCH unknown)
+ endif()
+ endif()
+
+ set(${output_var} "${ARCH}" PARENT_SCOPE)
+endfunction()
diff --git a/extern/libcds/build/cmake/description.txt b/extern/libcds/build/cmake/description.txt
new file mode 100644
index 0000000000..f4cdcbbeb4
--- /dev/null
+++ b/extern/libcds/build/cmake/description.txt
@@ -0,0 +1 @@
+libcds - Concurrent Data Structure C++ library
\ No newline at end of file
diff --git a/extern/libcds/build/cmake/post_install_script.sh b/extern/libcds/build/cmake/post_install_script.sh
new file mode 100644
index 0000000000..aea30415f7
--- /dev/null
+++ b/extern/libcds/build/cmake/post_install_script.sh
@@ -0,0 +1 @@
+ldconfig
\ No newline at end of file
diff --git a/extern/libcds/build/cmake/post_uninstall_script.sh b/extern/libcds/build/cmake/post_uninstall_script.sh
new file mode 100644
index 0000000000..aea30415f7
--- /dev/null
+++ b/extern/libcds/build/cmake/post_uninstall_script.sh
@@ -0,0 +1 @@
+ldconfig
\ No newline at end of file
diff --git a/extern/libcds/build/cmake/readme.md b/extern/libcds/build/cmake/readme.md
new file mode 100644
index 0000000000..6a5aa6a165
--- /dev/null
+++ b/extern/libcds/build/cmake/readme.md
@@ -0,0 +1,104 @@
+Building library with CMake
+===============
+
+CDS suports both in-source and out-of-source cmake build types. Now project uses:
+
+- CMake: general cross-platform building
+- CTest: all unit tests can be run in a standard way by *ctest* command
+- CPack: for making rpm/deb/nsys etc. packages
+
+Compiling and testing
+----------
+**Building out-of-source in "RELEASE" mode ("DEBUG" is default)**
+
+- Wherever create empty directory for building, for instance `libcds-debug`
+- Prepare: `cmake -DCMAKE_BUILD_TYPE=RELEASE `
+- Compile: `make -j4`
+- As a result you'll see shared and static cds libraries in the build directory
+
+**Warning**: We strongly recommend not to use static cds library. Static library is not tested and not maintained. You can use it on own risk.
+
+After using command cmake -L one can see some additional variables, that can activate additional features:
+
+- `WITH_TESTS:BOOL=OFF`: if you want to build library with unit testing support use *-DWITH_TESTS=ON* on prepare step. Be careful with this flag, because compile time will dramatically increase
+- `WITH_TESTS_COVERAGE:BOOL=OFF`: Analyze test coverage using gcov (only for gcc)
+- `WITH_BOOST_ATOMIC:BOOL=OFF`: Use boost atomics (only for boost >= 1.54)
+- `WITH_ASAN:BOOL=OFF`: compile libcds with AddressSanitizer instrumentation
+- `WITH_TSAN:BOOL=OFF`: compile libcds with ThreadSanitizer instrumentation
+
+Additional gtest hints (for unit and stress tests only):
+- `GTEST_INCLUDE_DIRS=path`: gives full `path` to gtest include dir.
+- `GTEST_LIBRARY=path`: gives full `path` to `libgtest.a`.
+
+
+Packaging
+----------
+
+In order to package library *CPack* is used, command *cpack -G * should create correspondent packages for particular operating system. Now the project supports building the following package types:
+
+- *RPM*: redhat-based linux distribs
+- *DEB*: debian-based linux distribs
+- *TGZ*: simple "*tgz*" archive with library and headers
+- *NSYS*: windows installer package (NSYS should be installed)
+
+"Live" building and packaging example
+----------
+- `git clone https://github.com/khizmax/libcds.git`
+- `mkdir libcds-release`
+- `cd libcds-release`
+- `cmake -DWITH\_TESTS=ON -DCMAKE\_BUILD_TYPE=RELEASE ../libcds`
+```
+ -- The C compiler identification is GNU 4.8.3
+ -- The CXX compiler identification is GNU 4.8.3
+ ...
+ -- Found Threads: TRUE
+ -- Boost version: 1.54.0
+ -- Found the following Boost libraries:
+ -- system
+ -- thread
+ Build type -- RELEASE
+ -- Configuring done
+ -- Generating done
+ -- Build files have been written to: <...>/libcds-release
+```
+- `make -j4`
+```
+ Scanning dependencies of target cds
+ Scanning dependencies of target test-common
+ Scanning dependencies of target cds-s
+ Scanning dependencies of target test-hdr-offsetof
+ [ 1%] Building CXX object CMakeFiles/cds-s.dir/src/hp_gc.cpp.o
+ ...
+ [100%] Built target test-hdr
+```
+
+- `ctest`
+```
+ Test project /home/kel/projects_cds/libcds-debug
+ Start 1: test-hdr
+ 1/7 Test #1: test-hdr ......................... Passed 1352.24 sec
+ Start 2: cdsu-misc
+ 2/7 Test #2: cdsu-misc ........................ Passed 0.00 sec
+ Start 3: cdsu-map
+ ...
+```
+
+- `cpack -G RPM`
+```
+ CPack: Create package using RPM
+ CPack: Install projects
+ CPack: - Run preinstall target for: cds
+ CPack: - Install project: cds
+ CPack: - Install component: devel
+ CPack: - Install component: lib
+ CPack: Create package
+ CPackRPM:Debug: Adding /usr/local to builtin omit list.
+ CPackRPM: Will use GENERATED spec file: /home/kel/projects_cds/libcds-debug/_CPack_Packages/Linux/RPM/SPECS/cds-devel.spec
+ CPackRPM: Will use GENERATED spec file: /home/kel/projects_cds/libcds-debug/_CPack_Packages/Linux/RPM/SPECS/cds-lib.spec
+ CPack: - package: /home/kel/projects_cds/libcds-debug/cds-2.1.0-1-devel.rpm generated.
+ CPack: - package: /home/kel/projects_cds/libcds-debug/cds-2.1.0-1-lib.rpm generated.
+```
+
+Future development
+----------
+- CDash: use CI system
\ No newline at end of file
diff --git a/extern/libcds/cds/algo/atomic.h b/extern/libcds/cds/algo/atomic.h
new file mode 100644
index 0000000000..907356107a
--- /dev/null
+++ b/extern/libcds/cds/algo/atomic.h
@@ -0,0 +1,496 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_CXX11_ATOMIC_H
+#define CDSLIB_CXX11_ATOMIC_H
+
+#include
+#include
+
+namespace cds {
+
+/// C++11 Atomic library support
+/** @anchor cds_cxx11_atomic
+ \p libcds can use the following implementations of the atomics:
+ - STL \p <atomic>. This is used by default
+ - \p boost.atomic for boost 1.54 and above. To use it you should define \p CDS_USE_BOOST_ATOMIC for
+ your compiler invocation, for example, for gcc specify \p -DCDS_USE_BOOST_ATOMIC
+ in command line
+ - \p libcds implementation of atomic operation according to C++11 standard as
+ specified in N3242, p.29.
+ \p libcds implementation is not the full standard compliant, it provides only C++ part of standard,
+ for example, \p libcds has no static initialization of the atomic variables and some other C features.
+ However, that imlementation is enough for the library purposes. Supported architecture: x86, amd64,
+ ia64 (Itanium) 64bit, 64bit Sparc. To use \p libcds atomic you should define \p CDS_USE_LIBCDS_ATOMIC
+ in the compiler command line (\p -DCDS_USE_LIBCDS_ATOMIC for gcc/clang).
+
+ @note For Clang compiler \p libcds doesn't use native \p libc++ \p <atomic> due some problems.
+ Instead, \p libcds atomic is used by default, or you can try to use \p boost.atomic.
+
+ The library defines \p atomics alias for atomic namespace:
+ - namespace atomics = std for STL
+ - namespace atomics = boost for \p boost.atomic
+ - namespace atomics = cds::cxx11_atomic for library-provided atomic implementation
+*/
+namespace cxx11_atomic {
+}} // namespace cds::cxx11_atomic
+
+//@cond
+#if defined(CDS_USE_BOOST_ATOMIC)
+ // boost atomic
+# include
+# if BOOST_VERSION >= 105400
+# include
+ namespace atomics = boost;
+# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace boost {
+# define CDS_CXX11_ATOMIC_END_NAMESPACE }
+# else
+# error "Boost version 1.54 or above is needed for boost.atomic"
+# endif
+#elif defined(CDS_USE_LIBCDS_ATOMIC)
+ // libcds atomic
+# include
+ namespace atomics = cds::cxx11_atomic;
+# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace cds { namespace cxx11_atomic {
+# define CDS_CXX11_ATOMIC_END_NAMESPACE }}
+#else
+ // Compiler provided C++11 atomic
+# include
+ namespace atomics = std;
+# define CDS_CXX11_ATOMIC_BEGIN_NAMESPACE namespace std {
+# define CDS_CXX11_ATOMIC_END_NAMESPACE }
+#endif
+//@endcond
+
+namespace cds {
+
+ /// Atomic primitives
+ /**
+ This namespace contains useful primitives derived from std::atomic.
+ */
+ namespace atomicity {
+
+ /// Atomic event counter.
+ /**
+ This class is based on std::atomic_size_t.
+ It uses relaxed memory ordering \p memory_order_relaxed and may be used as a statistic counter.
+ */
+ class event_counter
+ {
+ //@cond
+ atomics::atomic_size_t m_counter;
+ //@endcond
+
+ public:
+ typedef size_t value_type ; ///< Type of counter
+
+ public:
+ // Initializes event counter with zero
+ event_counter() noexcept
+ : m_counter(size_t(0))
+ {}
+
+ /// Assign operator
+ /**
+ Returns \p n.
+ */
+ value_type operator =(
+ value_type n ///< new value of the counter
+ ) noexcept
+ {
+ m_counter.exchange( n, atomics::memory_order_relaxed );
+ return n;
+ }
+
+ /// Addition
+ /**
+ Returns new value of the atomic counter.
+ */
+ size_t operator +=(
+ size_t n ///< addendum
+ ) noexcept
+ {
+ return m_counter.fetch_add( n, atomics::memory_order_relaxed ) + n;
+ }
+
+ /// Substraction
+ /**
+ Returns new value of the atomic counter.
+ */
+ size_t operator -=(
+ size_t n ///< subtrahend
+ ) noexcept
+ {
+ return m_counter.fetch_sub( n, atomics::memory_order_relaxed ) - n;
+ }
+
+ /// Get current value of the counter
+ operator size_t () const noexcept
+ {
+ return m_counter.load( atomics::memory_order_relaxed );
+ }
+
+ /// Preincrement
+ size_t operator ++() noexcept
+ {
+ return m_counter.fetch_add( 1, atomics::memory_order_relaxed ) + 1;
+ }
+ /// Postincrement
+ size_t operator ++(int) noexcept
+ {
+ return m_counter.fetch_add( 1, atomics::memory_order_relaxed );
+ }
+
+ /// Predecrement
+ size_t operator --() noexcept
+ {
+ return m_counter.fetch_sub( 1, atomics::memory_order_relaxed ) - 1;
+ }
+ /// Postdecrement
+ size_t operator --(int) noexcept
+ {
+ return m_counter.fetch_sub( 1, atomics::memory_order_relaxed );
+ }
+
+ /// Get current value of the counter
+ size_t get() const noexcept
+ {
+ return m_counter.load( atomics::memory_order_relaxed );
+ }
+
+ /// Resets the counter to 0
+ void reset() noexcept
+ {
+ m_counter.store( 0, atomics::memory_order_release );
+ }
+ };
+
+ /// Atomic item counter
+ /**
+ This class is simplified interface around \p std::atomic_size_t.
+ The class supports getting current value of the counter and increment/decrement its value.
+
+ See also: improved version that eliminates false sharing - \p cache_friendly_item_counter.
+ */
+ class item_counter
+ {
+ public:
+ typedef atomics::atomic_size_t atomic_type; ///< atomic type used
+ typedef size_t counter_type; ///< Integral item counter type (size_t)
+
+ private:
+ //@cond
+ atomic_type m_Counter; ///< Atomic item counter
+ //@endcond
+
+ public:
+ /// Default ctor initializes the counter to zero.
+ item_counter()
+ : m_Counter(counter_type(0))
+ {}
+
+ /// Returns current value of the counter
+ counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
+ {
+ return m_Counter.load( order );
+ }
+
+ /// Same as \ref value() with relaxed memory ordering
+ operator counter_type() const
+ {
+ return value();
+ }
+
+ /// Returns underlying atomic interface
+ atomic_type& getAtomic()
+ {
+ return m_Counter;
+ }
+
+ /// Returns underlying atomic interface (const)
+ const atomic_type& getAtomic() const
+ {
+ return m_Counter;
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( 1, order );
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( count, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ return m_Counter.fetch_sub( 1, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_sub( count, order );
+ }
+
+ /// Preincrement
+ counter_type operator ++()
+ {
+ return inc() + 1;
+ }
+ /// Postincrement
+ counter_type operator ++(int)
+ {
+ return inc();
+ }
+
+ /// Predecrement
+ counter_type operator --()
+ {
+ return dec() - 1;
+ }
+ /// Postdecrement
+ counter_type operator --(int)
+ {
+ return dec();
+ }
+
+ /// Increment by \p count
+ counter_type operator +=( counter_type count )
+ {
+ return inc( count ) + count;
+ }
+
+ /// Decrement by \p count
+ counter_type operator -=( counter_type count )
+ {
+ return dec( count ) - count;
+ }
+
+ /// Resets count to 0
+ void reset(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ m_Counter.store( 0, order );
+ }
+ };
+
+#if CDS_COMPILER == CDS_COMPILER_CLANG
+ // CLang unhappy: pad1_ and pad2_ - unused private field warning
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-private-field"
+#endif
+ /// Atomic cache-friendly item counter
+ /**
+ Atomic item counter with cache-line padding to avoid false sharing.
+ Adding cache-line padding before and after atomic counter eliminates the contention
+ in read path of many containers and can notably improve search operations in sets/maps.
+ */
+ class cache_friendly_item_counter
+ {
+ public:
+ typedef atomics::atomic_size_t atomic_type; ///< atomic type used
+ typedef size_t counter_type; ///< Integral item counter type (size_t)
+
+ private:
+ //@cond
+ char pad1_[cds::c_nCacheLineSize];
+ atomic_type m_Counter; ///< Atomic item counter
+ char pad2_[cds::c_nCacheLineSize - sizeof( atomic_type )];
+ //@endcond
+
+ public:
+ /// Default ctor initializes the counter to zero.
+ cache_friendly_item_counter()
+ : m_Counter(counter_type(0))
+ {}
+
+ /// Returns current value of the counter
+ counter_type value(atomics::memory_order order = atomics::memory_order_relaxed) const
+ {
+ return m_Counter.load( order );
+ }
+
+ /// Same as \ref value() with relaxed memory ordering
+ operator counter_type() const
+ {
+ return value();
+ }
+
+ /// Returns underlying atomic interface
+ atomic_type& getAtomic()
+ {
+ return m_Counter;
+ }
+
+ /// Returns underlying atomic interface (const)
+ const atomic_type& getAtomic() const
+ {
+ return m_Counter;
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc(atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( 1, order );
+ }
+
+ /// Increments the counter. Semantics: postincrement
+ counter_type inc( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_add( count, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ return m_Counter.fetch_sub( 1, order );
+ }
+
+ /// Decrements the counter. Semantics: postdecrement
+ counter_type dec( counter_type count, atomics::memory_order order = atomics::memory_order_relaxed )
+ {
+ return m_Counter.fetch_sub( count, order );
+ }
+
+ /// Preincrement
+ counter_type operator ++()
+ {
+ return inc() + 1;
+ }
+ /// Postincrement
+ counter_type operator ++(int)
+ {
+ return inc();
+ }
+
+ /// Predecrement
+ counter_type operator --()
+ {
+ return dec() - 1;
+ }
+ /// Postdecrement
+ counter_type operator --(int)
+ {
+ return dec();
+ }
+
+ /// Increment by \p count
+ counter_type operator +=( counter_type count )
+ {
+ return inc( count ) + count;
+ }
+
+ /// Decrement by \p count
+ counter_type operator -=( counter_type count )
+ {
+ return dec( count ) - count;
+ }
+
+ /// Resets count to 0
+ void reset(atomics::memory_order order = atomics::memory_order_relaxed)
+ {
+ m_Counter.store( 0, order );
+ }
+ };
+#if CDS_COMPILER == CDS_COMPILER_CLANG
+# pragma GCC diagnostic pop
+#endif
+
+ /// Empty item counter
+ /**
+ This class may be used instead of \ref item_counter when you do not need full \ref item_counter interface.
+ All methods of the class is empty and returns 0.
+
+ The object of this class should not be used in data structure that behavior significantly depends on item counting
+ (for example, in many hash map implementation).
+ */
+ class empty_item_counter {
+ public:
+ typedef size_t counter_type ; ///< Counter type
+ public:
+ /// Returns 0
+ static counter_type value(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ {
+ return 0;
+ }
+
+ /// Same as \ref value(), always returns 0.
+ operator counter_type() const
+ {
+ return value();
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type inc(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ {
+ return 0;
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type inc( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
+ {
+ return 0;
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type dec(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ {
+ return 0;
+ }
+
+ /// Dummy increment. Always returns 0
+ static counter_type dec( counter_type /*count*/, atomics::memory_order /*order*/ = atomics::memory_order_relaxed )
+ {
+ return 0;
+ }
+
+ /// Dummy pre-increment. Always returns 0
+ counter_type operator ++() const
+ {
+ return 0;
+ }
+ /// Dummy post-increment. Always returns 0
+ counter_type operator ++(int) const
+ {
+ return 0;
+ }
+
+ /// Dummy pre-decrement. Always returns 0
+ counter_type operator --() const
+ {
+ return 0;
+ }
+ /// Dummy post-decrement. Always returns 0
+ counter_type operator --(int) const
+ {
+ return 0;
+ }
+
+ /// Dummy increment by \p count, always returns 0
+ counter_type operator +=( counter_type count )
+ {
+ CDS_UNUSED( count );
+ return 0;
+ }
+
+ /// Dummy decrement by \p count, always returns 0
+ counter_type operator -=( counter_type count )
+ {
+ CDS_UNUSED( count );
+ return 0;
+ }
+
+ /// Dummy function
+ static void reset(atomics::memory_order /*order*/ = atomics::memory_order_relaxed)
+ {}
+ };
+ } // namespace atomicity
+} // namespace cds
+
+#endif // #ifndef CDSLIB_CXX11_ATOMIC_H
diff --git a/extern/libcds/cds/algo/backoff_strategy.h b/extern/libcds/cds/algo/backoff_strategy.h
new file mode 100644
index 0000000000..0aa229d4de
--- /dev/null
+++ b/extern/libcds/cds/algo/backoff_strategy.h
@@ -0,0 +1,439 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_BACKOFF_STRATEGY_H
+#define CDSLIB_BACKOFF_STRATEGY_H
+
+/*
+ Filename: backoff_strategy.h
+ Created 2007.03.01 by Maxim Khiszinsky
+
+ Description:
+ Generic back-off strategies
+
+ Editions:
+ 2007.03.01 Maxim Khiszinsky Created
+ 2008.10.02 Maxim Khiszinsky Backoff action transfers from contructor to operator() for all backoff schemas
+ 2009.09.10 Maxim Khiszinsky reset() function added
+*/
+
+#include // declval
+#include
+#include
+#include
+
+namespace cds {
+ /// Different backoff schemes
+ /**
+ Back-off schema may be used in lock-free algorithms when the algorithm cannot perform some action because a conflict
+ with the other concurrent operation is encountered. In this case current thread can do another work or can call
+ processor's performance hint.
+
+ The interface of back-off strategy is following:
+ \code
+ struct backoff_strategy {
+ void operator()();
+ template bool operator()( Predicate pr );
+ void reset();
+ };
+ \endcode
+
+ \p operator() operator calls back-off strategy's action. It is main part of back-off strategy.
+
+ Interruptible back-off template < typename Predicate > bool operator()( Predicate pr )
+ allows to interrupt back-off spinning if \p pr predicate returns \p true.
+ \p Predicate is a functor with the following interface:
+ \code
+ struct predicate {
+ bool operator()();
+ };
+ \endcode
+
+ \p reset() function resets internal state of back-off strategy to initial state. It is required for some
+ back-off strategies, for example, exponential back-off.
+ */
+ namespace backoff {
+
+ /// Empty backoff strategy. Do nothing
+ struct empty {
+ //@cond
+ void operator ()() const noexcept
+ {}
+
+ template
+ bool operator()(Predicate pr) const noexcept( noexcept(std::declval()()))
+ {
+ return pr();
+ }
+
+ static void reset() noexcept
+ {}
+ //@endcond
+ };
+
+ /// Switch to another thread (yield). Good for thread preemption architecture.
+ struct yield {
+ //@cond
+ void operator ()() const noexcept
+ {
+ std::this_thread::yield();
+ }
+
+ template
+ bool operator()(Predicate pr) const noexcept( noexcept(std::declval()()))
+ {
+ if ( pr())
+ return true;
+ operator()();
+ return false;
+ }
+
+ static void reset() noexcept
+ {}
+ //@endcond
+ };
+
+ /// Random pause
+ /**
+ This back-off strategy calls processor-specific pause hint instruction
+ if one is available for the processor architecture.
+ */
+ struct pause {
+ //@cond
+ void operator ()() const noexcept
+ {
+# ifdef CDS_backoff_hint_defined
+ platform::backoff_hint();
+# endif
+ }
+
+ template
+ bool operator()(Predicate pr) const noexcept( noexcept(std::declval()()))
+ {
+ if ( pr())
+ return true;
+ operator()();
+ return false;
+ }
+
+ static void reset() noexcept
+ {}
+ //@endcond
+ };
+
+ /// Processor hint back-off
+ /**
+ This back-off schema calls performance hint instruction if it is available for current processor.
+ Otherwise, it calls \p nop.
+ */
+ struct hint
+ {
+ //@cond
+ void operator ()() const noexcept
+ {
+# if defined(CDS_backoff_hint_defined)
+ platform::backoff_hint();
+# elif defined(CDS_backoff_nop_defined)
+ platform::backoff_nop();
+# endif
+ }
+
+ template
+ bool operator()(Predicate pr) const noexcept(noexcept(std::declval()()))
+ {
+ if ( pr())
+ return true;
+ operator()();
+ return false;
+ }
+
+ static void reset() noexcept
+ {}
+ //@endcond
+ };
+
+ /// \p backoff::exponential const traits
+ struct exponential_const_traits
+ {
+ typedef hint fast_path_backoff; ///< Fast-path back-off strategy
+ typedef yield slow_path_backoff; ///< Slow-path back-off strategy
+
+ enum: size_t {
+ lower_bound = 16, ///< Minimum spinning limit
+ upper_bound = 16 * 1024 ///< Maximum spinning limit
+ };
+ };
+
+ /// \p nackoff::exponential runtime traits
+ struct exponential_runtime_traits
+ {
+ typedef hint fast_path_backoff; ///< Fast-path back-off strategy
+ typedef yield slow_path_backoff; ///< Slow-path back-off strategy
+
+ static size_t lower_bound; ///< Minimum spinning limit, default is 16
+ static size_t upper_bound; ///< Maximum spinning limit, default is 16*1024
+ };
+
+ /// Exponential back-off
+ /**
+ This back-off strategy is composite. It consists of \p SpinBkoff and \p YieldBkoff
+ back-off strategy. In first, the strategy tries to apply repeatedly \p SpinBkoff
+ (spinning phase) until internal counter of failed attempts reaches its maximum
+ spinning value. Then, the strategy transits to high-contention phase
+ where it applies \p YieldBkoff until \p reset() is called.
+ On each spinning iteration the internal spinning counter is doubled.
+
+ Selecting the best value for maximum spinning limit is platform and application specific task.
+ The limits are described by \p Traits template parameter.
+ There are two types of \p Traits:
+ - constant traits \p exponential_const_traits - specifies the lower and upper limits
+ as a compile-time constants; to change the limits you should recompile your application
+ - runtime traits \p exponential_runtime_traits - specifies the limits as \p s_nExpMin
+ and \p s_nExpMax variables which can be changed at runtime to tune back-off strategy.
+
+ The traits class must declare two data member:
+ - \p lower_bound - the lower bound of spinning loop
+ - \p upper_bound - the upper boudn of spinning loop
+
+ You may use \p Traits template parameter to separate back-off implementations.
+ For example, you may define two \p exponential back-offs that is the best for your task A and B:
+ \code
+
+ #include
+ namespace bkoff = cds::backoff;
+
+ // the best bounds for task A
+ struct traits_A: public bkoff::exponential_const_traits
+ {
+ static size_t lower_bound;
+ static size_t upper_bound;
+ };
+ size_t traits_A::lower_bound = 1024;
+ size_t traits_A::upper_bound = 8 * 1024;
+
+ // the best bounds for task B
+ struct traits_B: public bkoff::exponential_const_traits
+ {
+ static size_t lower_bound;
+ static size_t upper_bound;
+ };
+ size_t traits_A::lower_bound = 16;
+ size_t traits_A::upper_bound = 1024;
+
+ // // define your back-off specialization
+ typedef bkoff::exponential expBackOffA;
+ typedef bkoff::exponential expBackOffB;
+ \endcode
+ */
+ template
+ class exponential
+ {
+ public:
+ typedef Traits traits; ///< Traits
+
+ typedef typename traits::fast_path_backoff spin_backoff ; ///< spin (fast-path) back-off strategy
+ typedef typename traits::slow_path_backoff yield_backoff ; ///< yield (slow-path) back-off strategy
+
+ protected:
+ size_t m_nExpCur ; ///< Current spin counter in range [traits::s_nExpMin, traits::s_nExpMax]
+
+ spin_backoff m_bkSpin ; ///< Spinning (fast-path) phase back-off strategy
+ yield_backoff m_bkYield ; ///< Yield phase back-off strategy
+
+ public:
+ /// Default ctor
+ exponential() noexcept
+ : m_nExpCur( traits::lower_bound )
+ {}
+
+ //@cond
+ void operator ()() noexcept(noexcept(std::declval()()) && noexcept(std::declval()()))
+ {
+ if ( m_nExpCur <= traits::upper_bound ) {
+ for ( size_t n = 0; n < m_nExpCur; ++n )
+ m_bkSpin();
+ m_nExpCur *= 2;
+ }
+ else
+ m_bkYield();
+ }
+
+ template
+ bool operator()( Predicate pr ) noexcept( noexcept(std::declval()()) && noexcept(std::declval()()) && noexcept(std::declval()()))
+ {
+ if ( m_nExpCur <= traits::upper_bound ) {
+ for ( size_t n = 0; n < m_nExpCur; ++n ) {
+ if ( m_bkSpin(pr))
+ return true;
+ }
+ m_nExpCur *= 2;
+ }
+ else
+ return m_bkYield(pr);
+ return false;
+ }
+
+ void reset() noexcept( noexcept( std::declval().reset()) && noexcept( std::declval().reset()))
+ {
+ m_nExpCur = traits::lower_bound;
+ m_bkSpin.reset();
+ m_bkYield.reset();
+ }
+ //@endcond
+ };
+
+ //@cond
+ template
+ struct make_exponential
+ {
+ struct traits: public exponential_const_traits
+ {
+ typedef FastPathBkOff fast_path_backoff;
+ typedef SlowPathBkOff slow_path_backoff;
+ };
+
+ typedef exponential type;
+ };
+
+ template
+ using make_exponential_t = typename make_exponential::type;
+ //@endcond
+
+ /// Constant traits for \ref delay back-off strategy
+ struct delay_const_traits
+ {
+ typedef std::chrono::milliseconds duration_type; ///< Timeout type
+ enum: unsigned {
+ timeout = 5 ///< Delay timeout
+ };
+ };
+
+ /// Runtime traits for \ref delay back-off strategy
+ struct delay_runtime_traits
+ {
+ typedef std::chrono::milliseconds duration_type; ///< Timeout type
+ static unsigned timeout; ///< Delay timeout, default 5
+ };
+
+ /// Delay back-off strategy
+ /**
+ Template arguments:
+ - \p Duration - duration type, default is \p std::chrono::milliseconds
+ - \p Traits - a class that defines default timeout.
+
+ Choosing the best value for th timeout is platform and application specific task.
+ The default values for timeout is provided by \p Traits class that should
+ \p timeout data member. There are two predefined \p Traits implementation:
+ - \p delay_const_traits - defines \p timeout as a constant (enum).
+ To change timeout you should recompile your application.
+ - \p delay_runtime_traits - specifies timeout as static data member that can be changed
+ at runtime to tune the back-off strategy.
+
+ You may use \p Traits template parameter to separate back-off implementations.
+ For example, you may define two \p delay back-offs for 5 and 10 ms timeout:
+ \code
+
+ #include
+ namespace bkoff = cds::backoff;
+
+ // 5ms delay
+ struct ms5
+ {
+ typedef std::chrono::milliseconds duration_type;
+ enum: unsigned { timeout = 5 };
+ };
+
+ // 10ms delay, runtime support
+ struct ms10
+ {
+ typedef std::chrono::milliseconds duration_type;
+ static unsigned timeout;
+ };
+ unsigned ms10::timeout = 10;
+
+ // define your back-off specialization
+ typedef bkoff::delay delay5;
+ typedef bkoff::delay delay10;
+
+ \endcode
+ */
+ template
+ class delay
+ {
+ public:
+ typedef Traits traits; ///< Traits
+ typedef typename Traits::duration_type duration_type; ///< Duration type (default \p std::chrono::milliseconds)
+
+ protected:
+ ///@cond
+ duration_type const timeout;
+ ///@endcond
+
+ public:
+ /// Default ctor takes the timeout from \p traits::timeout
+ delay() noexcept
+ : timeout( traits::timeout )
+ {}
+
+ /// Initializes timeout from \p nTimeout
+ constexpr explicit delay( unsigned int nTimeout ) noexcept
+ : timeout( nTimeout )
+ {}
+
+ //@cond
+ void operator()() const
+ {
+ std::this_thread::sleep_for( timeout );
+ }
+
+ template
+ bool operator()(Predicate pr) const
+ {
+ for ( unsigned int i = 0; i < traits::timeout; i += 2 ) {
+ if ( pr())
+ return true;
+ std::this_thread::sleep_for( duration_type( 2 ));
+ }
+ return false;
+ }
+
+ static void reset() noexcept
+ {}
+ //@endcond
+ };
+
+ //@cond
+ template
+ struct make_delay_of
+ {
+ struct traits {
+ typedef Duration duration_type;
+ enum: unsigned { timeout = Timeout };
+ };
+
+ typedef delay type;
+ };
+ //@endcond
+
+ /// Delay back-off strategy, template version
+ /**
+ This is a simplified version of \p backoff::delay class.
+ Template parameter \p Timeout sets a delay timeout of \p Duration unit.
+ */
+ template
+ using delay_of = typename make_delay_of< Timeout, Duration >::type;
+
+
+ /// Default backoff strategy
+ typedef exponential Default;
+
+ /// Default back-off strategy for lock primitives
+ typedef exponential LockDefault;
+
+ } // namespace backoff
+} // namespace cds
+
+
+#endif // #ifndef CDSLIB_BACKOFF_STRATEGY_H
diff --git a/extern/libcds/cds/algo/base.h b/extern/libcds/cds/algo/base.h
new file mode 100644
index 0000000000..2e7e55e052
--- /dev/null
+++ b/extern/libcds/cds/algo/base.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_BASE_H
+#define CDSLIB_ALGO_BASE_H
+
+#include
+
+namespace cds {
+
+ /// Different approaches and techniques for supporting high-concurrent data structure
+ namespace algo {}
+
+} // namespace cds
+
+#endif // #ifndef CDSLIB_ALGO_BASE_H
diff --git a/extern/libcds/cds/algo/bit_reversal.h b/extern/libcds/cds/algo/bit_reversal.h
new file mode 100644
index 0000000000..f2dece04a7
--- /dev/null
+++ b/extern/libcds/cds/algo/bit_reversal.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_BIT_REVERSAL_H
+#define CDSLIB_ALGO_BIT_REVERSAL_H
+
+#include
+
+ // Source: http://stackoverflow.com/questions/746171/best-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
+namespace cds { namespace algo {
+
+ /// Bit reversal algorithms
+ namespace bit_reversal {
+
+ /// SWAR algorithm (source: http://aggregate.org/MAGIC/#Bit%20Reversal)
+ struct swar {
+ /// 32bit
+ uint32_t operator()( uint32_t x ) const
+ {
+ x = ( ( ( x & 0xaaaaaaaa ) >> 1 ) | ( ( x & 0x55555555 ) << 1 ));
+ x = ( ( ( x & 0xcccccccc ) >> 2 ) | ( ( x & 0x33333333 ) << 2 ));
+ x = ( ( ( x & 0xf0f0f0f0 ) >> 4 ) | ( ( x & 0x0f0f0f0f ) << 4 ));
+ x = ( ( ( x & 0xff00ff00 ) >> 8 ) | ( ( x & 0x00ff00ff ) << 8 ));
+ return( ( x >> 16 ) | ( x << 16 ));
+ }
+
+ /// 64bit
+ uint64_t operator()( uint64_t x ) const
+ {
+ return ( static_cast( operator()( static_cast( x ))) << 32 ) // low 32bit
+ | ( static_cast( operator()( static_cast( x >> 32 )))); // high 32bit
+ }
+ };
+
+ /// Lookup table algorithm
+ struct lookup {
+ /// 32bit
+ uint32_t operator()( uint32_t x ) const
+ {
+ static uint8_t const table[] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+ };
+ static_assert( sizeof( table ) / sizeof( table[0] ) == 256, "Table size mismatch" );
+
+ return ( static_cast( table[x & 0xff] ) << 24 ) |
+ ( static_cast( table[( x >> 8 ) & 0xff] ) << 16 ) |
+ ( static_cast( table[( x >> 16 ) & 0xff] ) << 8 ) |
+ ( static_cast( table[( x >> 24 ) & 0xff] ));
+ }
+
+ /// 64bit
+ uint64_t operator()( uint64_t x ) const
+ {
+ return ( static_cast( operator()( static_cast( x ))) << 32 ) |
+ static_cast( operator()( static_cast( x >> 32 )));
+ }
+ };
+
+
+ /// Mul-Div algorithm for 32bit architectire
+
+ /// Mul-Div algorithm
+ struct muldiv {
+ //@cond
+ static uint8_t muldiv32_byte( uint8_t b )
+ {
+ return static_cast( ( ( b * 0x0802LU & 0x22110LU ) | ( b * 0x8020LU & 0x88440LU )) * 0x10101LU >> 16 );
+ }
+
+ static uint8_t muldiv64_byte( uint8_t b )
+ {
+ return static_cast( ( b * 0x0202020202ULL & 0x010884422010ULL ) % 1023 );
+ }
+
+ // for 32bit architecture
+ static uint32_t muldiv32( uint32_t x )
+ {
+ return static_cast( muldiv32_byte( static_cast( x >> 24 )))
+ | ( static_cast( muldiv32_byte( static_cast( x >> 16 ))) << 8 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 8 ))) << 16 )
+ | ( static_cast( muldiv32_byte( static_cast( x ))) << 24 );
+ }
+
+ static uint64_t muldiv32( uint64_t x )
+ {
+ return static_cast( muldiv32_byte( static_cast( x >> 56 )))
+ | ( static_cast( muldiv32_byte( static_cast( x >> 48 ))) << 8 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 40 ))) << 16 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 32 ))) << 24 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 24 ))) << 32 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 16 ))) << 40 )
+ | ( static_cast( muldiv32_byte( static_cast( x >> 8 ))) << 48 )
+ | ( static_cast( muldiv32_byte( static_cast( x ))) << 56 );
+ }
+
+ /// for 64bit architectire
+ static uint32_t muldiv64( uint32_t x )
+ {
+ return static_cast( muldiv64_byte( static_cast( x >> 24 )))
+ | ( static_cast( muldiv64_byte( static_cast( x >> 16 ))) << 8 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 8 ))) << 16 )
+ | ( static_cast( muldiv64_byte( static_cast( x ))) << 24 );
+ }
+
+ static uint64_t muldiv64( uint64_t x )
+ {
+ return static_cast( muldiv64_byte( static_cast( x >> 56 )))
+ | ( static_cast( muldiv64_byte( static_cast( x >> 48 ))) << 8 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 40 ))) << 16 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 32 ))) << 24 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 24 ))) << 32 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 16 ))) << 40 )
+ | ( static_cast( muldiv64_byte( static_cast( x >> 8 ))) << 48 )
+ | ( static_cast( muldiv64_byte( static_cast( x ))) << 56 );
+ }
+ //@endcond
+
+ /// 32bit
+ uint32_t operator()( uint32_t x ) const
+ {
+# if CDS_BUILD_BITS == 32
+ return muldiv32( x );
+# else
+ return muldiv64( x );
+# endif
+ }
+
+ /// 64bit
+ uint64_t operator()( uint64_t x ) const
+ {
+# if CDS_BUILD_BITS == 32
+ return muldiv32( x );
+# else
+ return muldiv64( x );
+# endif
+ }
+ };
+
+ } // namespace bit_reversal
+}} // namespace cds::algo
+
+#endif // #ifndef CDSLIB_ALGO_BIT_REVERSAL_H
diff --git a/extern/libcds/cds/algo/bitop.h b/extern/libcds/cds/algo/bitop.h
new file mode 100644
index 0000000000..abeff63075
--- /dev/null
+++ b/extern/libcds/cds/algo/bitop.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_BITOP_H
+#define CDSLIB_BITOP_H
+
+/*
+ Different bit algorithms:
+ LSB get least significant bit number
+ MSB get most significant bit number
+ bswap swap byte order of word
+ RBO reverse bit order of word
+
+ Editions:
+ 2007.10.08 Maxim.Khiszinsky Created
+*/
+
+#include
+#include
+
+namespace cds {
+ /// Bit operations
+ namespace bitop {
+
+ ///@cond none
+ namespace details {
+ template struct BitOps;
+
+ // 32-bit bit ops
+ template <> struct BitOps<4> {
+ typedef uint32_t TUInt;
+
+ static int MSB( TUInt x ) { return bitop::platform::msb32( x ); }
+ static int LSB( TUInt x ) { return bitop::platform::lsb32( x ); }
+ static int MSBnz( TUInt x ) { return bitop::platform::msb32nz( x ); }
+ static int LSBnz( TUInt x ) { return bitop::platform::lsb32nz( x ); }
+ static int SBC( TUInt x ) { return bitop::platform::sbc32( x ) ; }
+ static int ZBC( TUInt x ) { return bitop::platform::zbc32( x ) ; }
+
+ static TUInt RBO( TUInt x ) { return bitop::platform::rbo32( x ); }
+ static bool complement( TUInt& x, int nBit ) { return bitop::platform::complement32( &x, nBit ); }
+
+ static TUInt RandXorShift(TUInt x) { return bitop::platform::RandXorShift32(x); }
+ };
+
+ // 64-bit bit ops
+ template <> struct BitOps<8> {
+ typedef uint64_t TUInt;
+
+ static int MSB( TUInt x ) { return bitop::platform::msb64( x ); }
+ static int LSB( TUInt x ) { return bitop::platform::lsb64( x ); }
+ static int MSBnz( TUInt x ) { return bitop::platform::msb64nz( x ); }
+ static int LSBnz( TUInt x ) { return bitop::platform::lsb64nz( x ); }
+ static int SBC( TUInt x ) { return bitop::platform::sbc64( x ) ; }
+ static int ZBC( TUInt x ) { return bitop::platform::zbc64( x ) ; }
+
+ static TUInt RBO( TUInt x ) { return bitop::platform::rbo64( x ); }
+ static bool complement( TUInt& x, int nBit ) { return bitop::platform::complement64( &x, nBit ); }
+
+ static TUInt RandXorShift(TUInt x) { return bitop::platform::RandXorShift64(x); }
+ };
+ } // namespace details
+ //@endcond
+
+
+ /// Get least significant bit (LSB) number (1..32/64), 0 if nArg == 0
+ template
+ static inline int LSB( T nArg )
+ {
+ return details::BitOps< sizeof(T) >::LSB( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Get least significant bit (LSB) number (0..31/63)
+ /**
+ Precondition: nArg != 0
+ */
+ template
+ static inline int LSBnz( T nArg )
+ {
+ assert( nArg != 0 );
+ return details::BitOps< sizeof(T) >::LSBnz( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Get most significant bit (MSB) number (1..32/64), 0 if nArg == 0
+ template
+ static inline int MSB( T nArg )
+ {
+ return details::BitOps< sizeof(T) >::MSB( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Get most significant bit (MSB) number (0..31/63)
+ /**
+ Precondition: nArg != 0
+ */
+ template
+ static inline int MSBnz( T nArg )
+ {
+ assert( nArg != 0 );
+ return details::BitOps< sizeof(T) >::MSBnz( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Get non-zero bit count of a word
+ template
+ static inline int SBC( T nArg )
+ {
+ return details::BitOps< sizeof(T) >::SBC( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Get zero bit count of a word
+ template
+ static inline int ZBC( T nArg )
+ {
+ return details::BitOps< sizeof(T) >::ZBC( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Reverse bit order of \p nArg
+ template
+ static inline T RBO( T nArg )
+ {
+ return (T) details::BitOps< sizeof(T) >::RBO( (typename details::BitOps::TUInt) nArg );
+ }
+
+ /// Complement bit \p nBit in \p nArg
+ template
+ static inline bool complement( T& nArg, int nBit )
+ {
+ return details::BitOps< sizeof(T) >::complement( reinterpret_cast< typename details::BitOps::TUInt& >( nArg ), nBit );
+ }
+
+ /// Simple random number generator
+ template
+ static inline T RandXorShift( T x)
+ {
+ return (T) details::BitOps< sizeof(T) >::RandXorShift(x);
+ }
+
+ } // namespace bitop
+} //namespace cds
+
+#endif // #ifndef CDSLIB_BITOP_H
+
diff --git a/extern/libcds/cds/algo/elimination.h b/extern/libcds/cds/algo/elimination.h
new file mode 100644
index 0000000000..cfa694b828
--- /dev/null
+++ b/extern/libcds/cds/algo/elimination.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_ELIMINATION_H
+#define CDSLIB_ALGO_ELIMINATION_H
+
+#include
+#include
+#include
+#include
+
+namespace cds { namespace algo {
+
+ /// Elimination technique
+ /** @anchor cds_elimination_description
+ Elimination technique allows highly distributed coupling and execution of operations with reverse
+ semantics like the pushes and pops on a stack. If a push followed by a pop are performed
+ on a stack, the data structure's state does not change (similarly for a pop followed by a push).
+ This means that if one can cause pairs of pushes and pops to meet and pair up in
+ separate locations, the threads can exchange values without having to touch a centralized structure
+ since they have anyhow "eliminated" each other's effect on it. Elimination can be implemented
+ by using a collision array in which threads pick random locations in order to try and collide.
+ Pairs of threads that "collide" in some location run through a synchronization protocol,
+ and all such disjoint collisions can be performed in parallel. If a thread has not met another
+ in the selected location or if it met a thread with an operation that cannot be eliminated
+ (such as two push operations), an alternative scheme must be used.
+ */
+ namespace elimination {
+
+ /// Base class describing an operation for eliminating
+ /**
+ This class contains some debugng info.
+ Actual operation descriptor depends on real container and its interface.
+ */
+ struct operation_desc
+ {
+ record * pOwner; ///< Owner of the descriptor
+ };
+
+ /// Acquires elimination record for the current thread
+ template
+ static inline record * init_record( OperationDesc& op )
+ {
+ record& rec = cds::threading::elimination_record();
+ assert( rec.is_free());
+ op.pOwner = &rec;
+ rec.pOp = static_cast( &op );
+ return &rec;
+ }
+
+ /// Releases elimination record for the current thread
+ static inline void clear_record()
+ {
+ cds::threading::elimination_record().pOp = nullptr;
+ }
+ } // namespace elimination
+}} // namespace cds::algo
+
+#endif // CDSLIB_ALGO_ELIMINATION_H
diff --git a/extern/libcds/cds/algo/elimination_opt.h b/extern/libcds/cds/algo/elimination_opt.h
new file mode 100644
index 0000000000..61ec6ccf17
--- /dev/null
+++ b/extern/libcds/cds/algo/elimination_opt.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_ELIMINATION_OPT_H
+#define CDSLIB_ALGO_ELIMINATION_OPT_H
+
+#include
+
+namespace cds { namespace opt {
+
+ /// Enable \ref cds_elimination_description "elimination back-off" for the container
+ template
+ struct enable_elimination {
+ //@cond
+ template struct pack: public Base
+ {
+ static constexpr const bool enable_elimination = Enable;
+ };
+ //@endcond
+ };
+
+ /// \ref cds_elimination_description "Elimination back-off strategy" option setter
+ /**
+ Back-off strategy for elimination.
+ Usually, elimination back-off strategy is \p cds::backoff::delay.
+ */
+ template
+ struct elimination_backoff {
+ //@cond
+ template struct pack: public Base
+ {
+ typedef Type elimination_backoff;
+ };
+ //@endcond
+ };
+}} // namespace cds::opt
+
+#endif // #ifndef CDSLIB_ALGO_ELIMINATION_OPT_H
diff --git a/extern/libcds/cds/algo/elimination_tls.h b/extern/libcds/cds/algo/elimination_tls.h
new file mode 100644
index 0000000000..71b60923d0
--- /dev/null
+++ b/extern/libcds/cds/algo/elimination_tls.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_ELIMINATION_TLS_H
+#define CDSLIB_ALGO_ELIMINATION_TLS_H
+
+#include
+
+namespace cds { namespace algo { namespace elimination {
+
+ // Forwards
+ struct operation_desc;
+
+ /// Per-thread elimination record
+ /** @headerfile cds/algo/elimination.h
+ */
+ struct record
+ {
+ operation_desc * pOp ; ///< Operation descriptor
+
+ /// Initialization
+ record()
+ : pOp( nullptr )
+ {}
+
+ /// Checks if the record is free
+ bool is_free() const
+ {
+ return pOp == nullptr;
+ }
+ };
+
+}}} // cds::algo::elimination
+
+#endif // #ifndef CDSLIB_ALGO_ELIMINATION_TLS_H
diff --git a/extern/libcds/cds/algo/flat_combining.h b/extern/libcds/cds/algo/flat_combining.h
new file mode 100644
index 0000000000..1e6f4bf0cf
--- /dev/null
+++ b/extern/libcds/cds/algo/flat_combining.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_FLAT_COMBINING_H
+#define CDSLIB_ALGO_FLAT_COMBINING_H
+
+#include
+
+#endif // #ifndef CDSLIB_ALGO_FLAT_COMBINING_H
diff --git a/extern/libcds/cds/algo/flat_combining/defs.h b/extern/libcds/cds/algo/flat_combining/defs.h
new file mode 100644
index 0000000000..ffd0d0170a
--- /dev/null
+++ b/extern/libcds/cds/algo/flat_combining/defs.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_FLAT_COMBINING_DEFS_H
+#define CDSLIB_ALGO_FLAT_COMBINING_DEFS_H
+
+#include
+
+
+namespace cds { namespace algo { namespace flat_combining {
+
+ /// Special values of \p publication_record::nRequest
+ enum request_value
+ {
+ req_EmptyRecord, ///< Publication record is empty
+ req_Response, ///< Operation is done
+
+ req_Operation ///< First operation id for derived classes
+ };
+
+ /// \p publication_record state
+ enum record_state {
+ inactive, ///< Record is inactive
+ active, ///< Record is active
+ removed ///< Record should be removed
+ };
+
+ /// Record of publication list
+ /**
+ Each data structure based on flat combining contains a class derived from \p %publication_record
+ */
+ struct publication_record {
+ atomics::atomic nRequest; ///< Request field (depends on data structure)
+ atomics::atomic nState; ///< Record state: inactive, active, removed
+ atomics::atomic nAge; ///< Age of the record
+ atomics::atomic pNext; ///< Next record in active publication list
+ atomics::atomic pNextAllocated; ///< Next record in allocated publication list
+
+ /// Initializes publication record
+ publication_record()
+ : nRequest( req_EmptyRecord )
+ , nAge( 0 )
+ , pNext( nullptr )
+ , pNextAllocated( nullptr )
+ {
+ nState.store( inactive, atomics::memory_order_release );
+ }
+
+ /// Returns the value of \p nRequest field
+ unsigned int op( atomics::memory_order mo = atomics::memory_order_relaxed ) const
+ {
+ return nRequest.load( mo );
+ }
+
+ /// Checks if the operation is done
+ bool is_done() const
+ {
+ return nRequest.load( atomics::memory_order_relaxed ) == req_Response;
+ }
+ };
+
+
+}}} // namespace cds::algo::flat_combining
+
+#endif // CDSLIB_ALGO_FLAT_COMBINING_DEFS_H
diff --git a/extern/libcds/cds/algo/flat_combining/kernel.h b/extern/libcds/cds/algo/flat_combining/kernel.h
new file mode 100644
index 0000000000..48a32b97a8
--- /dev/null
+++ b/extern/libcds/cds/algo/flat_combining/kernel.h
@@ -0,0 +1,875 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H
+#define CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace cds { namespace algo {
+
+ /// @defgroup cds_flat_combining_intrusive Intrusive flat combining containers
+ /// @defgroup cds_flat_combining_container Non-intrusive flat combining containers
+
+ /// Flat combining
+ /**
+ @anchor cds_flat_combining_description
+ Flat combining (FC) technique is invented by Hendler, Incze, Shavit and Tzafrir in their paper
+ [2010] "Flat Combining and the Synchronization-Parallelism Tradeoff".
+ The technique converts a sequential data structure to its concurrent implementation.
+ A few structures are added to the sequential implementation: a global lock,
+ a count of the number of combining passes, and a pointer to the head
+ of a publication list. The publication list is a list of thread-local records
+ of a size proportional to the number of threads that are concurrently accessing the shared object.
+
+ Each thread \p t accessing the structure to perform an invocation of some method \p f()
+ on the shared object executes the following sequence of steps:
+
+
Write the invocation opcode and parameters (if any) of the method \p f() to be applied
+ sequentially to the shared object in the request field of your thread local publication
+ record (there is no need to use a load-store memory barrier). The request field will later
+ be used to receive the response. If your thread local publication record is marked as active
+ continue to step 2, otherwise continue to step 5.
+
Check if the global lock is taken. If so (another thread is an active combiner), spin on the request
+ field waiting for a response to the invocation (one can add a yield at this point to allow other threads
+ on the same core to run). Once in a while while spinning check if the lock is still taken and that your
+ record is active (you may use any of \p wait_strategy instead of spinning). If your record is inactive proceed to step 5.
+ Once the response is available, reset the request field to null and return the response.
+
If the lock is not taken, attempt to acquire it and become a combiner. If you fail,
+ return to spinning in step 2.
+
Otherwise, you hold the lock and are a combiner.
+
+
Increment the combining pass count by one.
+
Execute a \p fc_apply() by traversing the publication list from the head,
+ combining all non-null method call invocations, setting the age of each of these records
+ to the current count, applying the combined method calls to the structure D, and returning
+ responses to all the invocations. This traversal is guaranteed to be wait-free.
+
If the count is such that a cleanup needs to be performed, traverse the publication
+ list from the head. Starting from the second item (we always leave the item pointed to
+ by the head in the list), remove from the publication list all records whose age is
+ much smaller than the current count. This is done by removing the node and marking it
+ as inactive.
+
Release the lock.
+
+
If you have no thread local publication record allocate one, marked as active. If you already
+ have one marked as inactive, mark it as active. Execute a store-load memory barrier. Proceed to insert
+ the record into the list with a successful CAS to the head. Then proceed to step 1.
+
+
+ As the test results show, the flat combining technique is suitable for non-intrusive containers
+ like stack, queue, deque. For intrusive concurrent containers the flat combining demonstrates
+ less impressive results.
+
+ \ref cds_flat_combining_container "List of FC-based containers" in libcds.
+
+ \ref cds_flat_combining_intrusive "List of intrusive FC-based containers" in libcds.
+ */
+ namespace flat_combining {
+
+ /// Flat combining internal statistics
+ template
+ struct stat
+ {
+ typedef Counter counter_type; ///< Event counter type
+
+ counter_type m_nOperationCount ; ///< How many operations have been performed
+ counter_type m_nCombiningCount ; ///< Combining call count
+ counter_type m_nCompactPublicationList; ///< Count of publication list compacting
+ counter_type m_nDeactivatePubRecord; ///< How many publication records were deactivated during compacting
+ counter_type m_nActivatePubRecord; ///< Count of publication record activating
+ counter_type m_nPubRecordCreated ; ///< Count of created publication records
+ counter_type m_nPubRecordDeleted ; ///< Count of deleted publication records
+ counter_type m_nPassiveWaitCall; ///< Count of passive waiting call (\p kernel::wait_for_combining())
+ counter_type m_nPassiveWaitIteration;///< Count of iteration inside passive waiting
+ counter_type m_nPassiveWaitWakeup; ///< Count of forcing wake-up of passive wait cycle
+ counter_type m_nInvokeExclusive; ///< Count of call \p kernel::invoke_exclusive()
+ counter_type m_nWakeupByNotifying; ///< How many times the passive thread be waked up by a notification
+ counter_type m_nPassiveToCombiner; ///< How many times the passive thread becomes the combiner
+
+ /// Returns current combining factor
+ /**
+ Combining factor is how many operations perform in one combine pass:
+ combining_factor := m_nOperationCount / m_nCombiningCount
+ */
+ double combining_factor() const
+ {
+ return m_nCombiningCount.get() ? double( m_nOperationCount.get()) / m_nCombiningCount.get() : 0.0;
+ }
+
+ //@cond
+ void onOperation() { ++m_nOperationCount; }
+ void onCombining() { ++m_nCombiningCount; }
+ void onCompactPublicationList() { ++m_nCompactPublicationList; }
+ void onDeactivatePubRecord() { ++m_nDeactivatePubRecord; }
+ void onActivatePubRecord() { ++m_nActivatePubRecord; }
+ void onCreatePubRecord() { ++m_nPubRecordCreated; }
+ void onDeletePubRecord() { ++m_nPubRecordDeleted; }
+ void onPassiveWait() { ++m_nPassiveWaitCall; }
+ void onPassiveWaitIteration() { ++m_nPassiveWaitIteration; }
+ void onPassiveWaitWakeup() { ++m_nPassiveWaitWakeup; }
+ void onInvokeExclusive() { ++m_nInvokeExclusive; }
+ void onWakeupByNotifying() { ++m_nWakeupByNotifying; }
+ void onPassiveToCombiner() { ++m_nPassiveToCombiner; }
+
+ //@endcond
+ };
+
+ /// Flat combining dummy internal statistics
+ struct empty_stat
+ {
+ //@cond
+ void onOperation() const {}
+ void onCombining() const {}
+ void onCompactPublicationList() const {}
+ void onDeactivatePubRecord() const {}
+ void onActivatePubRecord() const {}
+ void onCreatePubRecord() const {}
+ void onDeletePubRecord() const {}
+ void onPassiveWait() const {}
+ void onPassiveWaitIteration() const {}
+ void onPassiveWaitWakeup() const {}
+ void onInvokeExclusive() const {}
+ void onWakeupByNotifying() const {}
+ void onPassiveToCombiner() const {}
+ //@endcond
+ };
+
+ /// Type traits of \ref kernel class
+ /**
+ You can define different type traits for \ref kernel
+ by specifying your struct based on \p %traits
+ or by using \ref make_traits metafunction.
+ */
+ struct traits
+ {
+ typedef cds::sync::spin lock_type; ///< Lock type
+ typedef cds::algo::flat_combining::wait_strategy::backoff< cds::backoff::delay_of<2>> wait_strategy; ///< Wait strategy
+ typedef CDS_DEFAULT_ALLOCATOR allocator; ///< Allocator used for TLS data (allocating \p publication_record derivatives)
+ typedef empty_stat stat; ///< Internal statistics
+ typedef opt::v::relaxed_ordering memory_model; ///< /// C++ memory ordering model
+ };
+
+ /// Metafunction converting option list to traits
+ /**
+ \p Options are:
+ - \p opt::lock_type - mutex type, default is \p cds::sync::spin
+ - \p opt::wait_strategy - wait strategy, see \p wait_strategy namespace, default is \p wait_strategy::backoff.
+ - \p opt::allocator - allocator type, default is \ref CDS_DEFAULT_ALLOCATOR
+ - \p opt::stat - internal statistics, possible type: \ref stat, \ref empty_stat (the default)
+ - \p opt::memory_model - C++ memory ordering model.
+ List of all available memory ordering see \p opt::memory_model.
+ Default is \p cds::opt::v::relaxed_ordering
+ */
+ template
+ struct make_traits {
+# ifdef CDS_DOXYGEN_INVOKED
+ typedef implementation_defined type ; ///< Metafunction result
+# else
+ typedef typename cds::opt::make_options<
+ typename cds::opt::find_type_traits< traits, Options... >::type
+ ,Options...
+ >::type type;
+# endif
+ };
+
+ /// The kernel of flat combining
+ /**
+ Template parameters:
+ - \p PublicationRecord - a type derived from \ref publication_record
+ - \p Traits - a type traits of flat combining, default is \p flat_combining::traits.
+ \ref make_traits metafunction can be used to create type traits
+
+ The kernel object should be a member of a container class. The container cooperates with flat combining
+ kernel object. There are two ways to interact with the kernel:
+ - One-by-one processing the active records of the publication list. This mode provides by \p combine() function:
+ the container acquires its publication record by \p acquire_record(), fills its fields and calls
+ \p combine() function of its kernel object. If the current thread becomes a combiner, the kernel
+ calls \p fc_apply() function of the container for each active non-empty record. Then, the container
+ should release its publication record by \p release_record(). Only one pass through the publication
+ list is possible.
+ - Batch processing - \p batch_combine() function. It this mode the container obtains access
+ to entire publication list. This mode allows the container to perform an elimination, for example,
+ the stack can collide \p push() and \p pop() requests. The sequence of invocations is the following:
+ the container acquires its publication record by \p acquire_record(), fills its field and call
+ \p batch_combine() function of its kernel object. If the current thread becomes a combiner,
+ the kernel calls \p fc_process() function of the container passing two iterators pointing to
+ the begin and the end of publication list (see \ref iterator class). The iterators allow
+ multiple pass through active records of publication list. For each processed record the container
+ should call \p operation_done() function. On the end, the container should release
+ its record by \p release_record().
+ */
+ template <
+ typename PublicationRecord
+ ,typename Traits = traits
+ >
+ class kernel
+ {
+ public:
+ typedef Traits traits; ///< Type traits
+ typedef typename traits::lock_type global_lock_type; ///< Global lock type
+ typedef typename traits::wait_strategy wait_strategy; ///< Wait strategy type
+ typedef typename traits::allocator allocator; ///< Allocator type (used for allocating publication_record_type data)
+ typedef typename traits::stat stat; ///< Internal statistics
+ typedef typename traits::memory_model memory_model; ///< C++ memory model
+
+ typedef typename wait_strategy::template make_publication_record::type publication_record_type; ///< Publication record type
+
+ protected:
+ //@cond
+ typedef cds::details::Allocator< publication_record_type, allocator > cxx11_allocator; ///< internal helper cds::details::Allocator
+ typedef std::lock_guard lock_guard;
+ //@endcond
+
+ protected:
+ atomics::atomic m_nCount; ///< Total count of combining passes. Used as an age.
+ publication_record_type* m_pHead; ///< Head of active publication list
+ publication_record_type* m_pAllocatedHead; ///< Head of allocated publication list
+ boost::thread_specific_ptr< publication_record_type > m_pThreadRec; ///< Thread-local publication record
+ mutable global_lock_type m_Mutex; ///< Global mutex
+ mutable stat m_Stat; ///< Internal statistics
+ unsigned int const m_nCompactFactor; ///< Publication list compacting factor (the list will be compacted through \p %m_nCompactFactor combining passes)
+ unsigned int const m_nCombinePassCount; ///< Number of combining passes
+ wait_strategy m_waitStrategy; ///< Wait strategy
+
+ public:
+ /// Initializes the object
+ /**
+ Compact factor = 1024
+
+ Combiner pass count = 8
+ */
+ kernel()
+ : kernel( 1024, 8 )
+ {}
+
+ /// Initializes the object
+ kernel(
+ unsigned int nCompactFactor ///< Publication list compacting factor (the list will be compacted through \p nCompactFactor combining passes)
+ ,unsigned int nCombinePassCount ///< Number of combining passes for combiner thread
+ )
+ : m_nCount(0)
+ , m_pHead( nullptr )
+ , m_pAllocatedHead( nullptr )
+ , m_pThreadRec( tls_cleanup )
+ , m_nCompactFactor( static_cast( cds::beans::ceil2( static_cast( nCompactFactor )) - 1 )) // binary mask
+ , m_nCombinePassCount( nCombinePassCount )
+ {
+ assert( m_pThreadRec.get() == nullptr );
+ publication_record_type* pRec = cxx11_allocator().New();
+ m_pAllocatedHead =
+ m_pHead = pRec;
+ m_pThreadRec.reset( pRec );
+ m_Stat.onCreatePubRecord();
+ }
+
+ /// Destroys the object and all publication records
+ ~kernel()
+ {
+ m_pThreadRec.reset(); // calls tls_cleanup()
+
+ // delete all publication records
+ for ( publication_record* p = m_pAllocatedHead; p; ) {
+ publication_record * pRec = p;
+ p = p->pNextAllocated.load( memory_model::memory_order_relaxed );
+ free_publication_record( static_cast( pRec ));
+ }
+ }
+
+ /// Gets publication list record for the current thread
+ /**
+ If there is no publication record for the current thread
+ the function allocates it.
+ */
+ publication_record_type * acquire_record()
+ {
+ publication_record_type * pRec = m_pThreadRec.get();
+ if ( !pRec ) {
+ // Allocate new publication record
+ pRec = cxx11_allocator().New();
+ m_pThreadRec.reset( pRec );
+ m_Stat.onCreatePubRecord();
+
+ // Insert in allocated list
+ assert( m_pAllocatedHead != nullptr );
+ publication_record* p = m_pAllocatedHead->pNextAllocated.load( memory_model::memory_order_relaxed );
+ do {
+ pRec->pNextAllocated.store( p, memory_model::memory_order_release );
+ } while ( !m_pAllocatedHead->pNextAllocated.compare_exchange_weak( p, pRec, memory_model::memory_order_release, atomics::memory_order_acquire ));
+
+ publish( pRec );
+ }
+ else if ( pRec->nState.load( memory_model::memory_order_acquire ) != active )
+ publish( pRec );
+
+ assert( pRec->op() == req_EmptyRecord );
+
+ return pRec;
+ }
+
+ /// Marks publication record for the current thread as empty
+ void release_record( publication_record_type * pRec )
+ {
+ assert( pRec->is_done());
+ pRec->nRequest.store( req_EmptyRecord, memory_model::memory_order_release );
+ }
+
+ /// Trying to execute operation \p nOpId
+ /**
+ \p pRec is the publication record acquiring by \ref acquire_record earlier.
+ \p owner is a container that is owner of flat combining kernel object.
+ As a result the current thread can become a combiner or can wait for
+ another combiner performs \p pRec operation.
+
+ If the thread becomes a combiner, the kernel calls \p owner.fc_apply
+ for each active non-empty publication record.
+ */
+ template
+ void combine( unsigned int nOpId, publication_record_type * pRec, Container& owner )
+ {
+ assert( nOpId >= req_Operation );
+ assert( pRec );
+
+ pRec->nRequest.store( nOpId, memory_model::memory_order_release );
+ m_Stat.onOperation();
+
+ try_combining( owner, pRec );
+ }
+
+ /// Trying to execute operation \p nOpId in batch-combine mode
+ /**
+ \p pRec is the publication record acquiring by \p acquire_record() earlier.
+ \p owner is a container that owns flat combining kernel object.
+ As a result the current thread can become a combiner or can wait for
+ another combiner performs \p pRec operation.
+
+ If the thread becomes a combiner, the kernel calls \p owner.fc_process()
+ giving the container the full access over publication list. This function
+ is useful for an elimination technique if the container supports any kind of
+ that. The container can perform multiple pass through publication list.
+
+ \p owner.fc_process() has two arguments - forward iterators on begin and end of
+ publication list, see \ref iterator class. For each processed record the container
+ should call \p operation_done() function to mark the record as processed.
+
+ On the end of \p %batch_combine the \p combine() function is called
+ to process rest of publication records.
+ */
+ template
+ void batch_combine( unsigned int nOpId, publication_record_type* pRec, Container& owner )
+ {
+ assert( nOpId >= req_Operation );
+ assert( pRec );
+
+ pRec->nRequest.store( nOpId, memory_model::memory_order_release );
+ m_Stat.onOperation();
+
+ try_batch_combining( owner, pRec );
+ }
+
+ /// Invokes \p Func in exclusive mode
+ /**
+ Some operation in flat combining containers should be called in exclusive mode
+ i.e the current thread should become the combiner to process the operation.
+ The typical example is \p empty() function.
+
+ \p %invoke_exclusive() allows do that: the current thread becomes the combiner,
+ invokes \p f exclusively but unlike a typical usage the thread does not process any pending request.
+ Instead, after end of \p f call the current thread wakes up a pending thread if any.
+ */
+ template
+ void invoke_exclusive( Func f )
+ {
+ {
+ lock_guard l( m_Mutex );
+ f();
+ }
+ m_waitStrategy.wakeup( *this );
+ m_Stat.onInvokeExclusive();
+ }
+
+ /// Marks \p rec as executed
+ /**
+ This function should be called by container if \p batch_combine() mode is used.
+ For usual combining (see \p combine()) this function is excess.
+ */
+ void operation_done( publication_record& rec )
+ {
+ rec.nRequest.store( req_Response, memory_model::memory_order_release );
+ m_waitStrategy.notify( *this, static_cast( rec ));
+ }
+
+ /// Internal statistics
+ stat const& statistics() const
+ {
+ return m_Stat;
+ }
+
+ //@cond
+ // For container classes based on flat combining
+ stat& internal_statistics() const
+ {
+ return m_Stat;
+ }
+ //@endcond
+
+ /// Returns the compact factor
+ unsigned int compact_factor() const
+ {
+ return m_nCompactFactor + 1;
+ }
+
+ /// Returns number of combining passes for combiner thread
+ unsigned int combine_pass_count() const
+ {
+ return m_nCombinePassCount;
+ }
+
+ public:
+ /// Publication list iterator
+ /**
+ Iterators are intended for batch processing by container's
+ \p fc_process function.
+ The iterator allows iterate through active publication list.
+ */
+ class iterator
+ {
+ //@cond
+ friend class kernel;
+ publication_record_type * m_pRec;
+ //@endcond
+
+ protected:
+ //@cond
+ iterator( publication_record_type * pRec )
+ : m_pRec( pRec )
+ {
+ skip_inactive();
+ }
+
+ void skip_inactive()
+ {
+ while ( m_pRec && (m_pRec->nState.load( memory_model::memory_order_acquire ) != active
+ || m_pRec->op( memory_model::memory_order_relaxed) < req_Operation ))
+ {
+ m_pRec = static_cast(m_pRec->pNext.load( memory_model::memory_order_acquire ));
+ }
+ }
+ //@endcond
+
+ public:
+ /// Initializes an empty iterator object
+ iterator()
+ : m_pRec( nullptr )
+ {}
+
+ /// Copy ctor
+ iterator( iterator const& src )
+ : m_pRec( src.m_pRec )
+ {}
+
+ /// Pre-increment
+ iterator& operator++()
+ {
+ assert( m_pRec );
+ m_pRec = static_cast( m_pRec->pNext.load( memory_model::memory_order_acquire ));
+ skip_inactive();
+ return *this;
+ }
+
+ /// Post-increment
+ iterator operator++(int)
+ {
+ assert( m_pRec );
+ iterator it(*this);
+ ++(*this);
+ return it;
+ }
+
+ /// Dereference operator, can return \p nullptr
+ publication_record_type* operator ->()
+ {
+ return m_pRec;
+ }
+
+ /// Dereference operator, the iterator should not be an end iterator
+ publication_record_type& operator*()
+ {
+ assert( m_pRec );
+ return *m_pRec;
+ }
+
+ /// Iterator equality
+ friend bool operator==( iterator it1, iterator it2 )
+ {
+ return it1.m_pRec == it2.m_pRec;
+ }
+
+ /// Iterator inequality
+ friend bool operator!=( iterator it1, iterator it2 )
+ {
+ return !( it1 == it2 );
+ }
+ };
+
+ /// Returns an iterator to the first active publication record
+ iterator begin() { return iterator(m_pHead); }
+
+ /// Returns an iterator to the end of publication list. Should not be dereferenced.
+ iterator end() { return iterator(); }
+
+ public:
+ /// Gets current value of \p rec.nRequest
+ /**
+ This function is intended for invoking from a wait strategy
+ */
+ int get_operation( publication_record& rec )
+ {
+ return rec.op( memory_model::memory_order_acquire );
+ }
+
+ /// Wakes up any waiting thread
+ /**
+ This function is intended for invoking from a wait strategy
+ */
+ void wakeup_any()
+ {
+ publication_record* pRec = m_pHead;
+ while ( pRec ) {
+ if ( pRec->nState.load( memory_model::memory_order_acquire ) == active
+ && pRec->op( memory_model::memory_order_acquire ) >= req_Operation )
+ {
+ m_waitStrategy.notify( *this, static_cast( *pRec ));
+ break;
+ }
+ pRec = pRec->pNext.load( memory_model::memory_order_acquire );
+ }
+ }
+
+ private:
+ //@cond
+ static void tls_cleanup( publication_record_type* pRec )
+ {
+ // Thread done
+ // pRec that is TLS data should be excluded from publication list
+ pRec->nState.store( removed, memory_model::memory_order_release );
+ }
+
+ void free_publication_record( publication_record_type* pRec )
+ {
+ cxx11_allocator().Delete( pRec );
+ m_Stat.onDeletePubRecord();
+ }
+
+ void publish( publication_record_type* pRec )
+ {
+ assert( pRec->nState.load( memory_model::memory_order_relaxed ) == inactive );
+
+ pRec->nAge.store( m_nCount.load(memory_model::memory_order_relaxed), memory_model::memory_order_relaxed );
+ pRec->nState.store( active, memory_model::memory_order_relaxed );
+
+ // Insert record to publication list
+ if ( m_pHead != static_cast(pRec)) {
+ publication_record * p = m_pHead->pNext.load( memory_model::memory_order_relaxed );
+ if ( p != static_cast( pRec )) {
+ do {
+ pRec->pNext.store( p, memory_model::memory_order_release );
+ // Failed CAS changes p
+ } while ( !m_pHead->pNext.compare_exchange_weak( p, static_cast(pRec),
+ memory_model::memory_order_release, atomics::memory_order_acquire ));
+ m_Stat.onActivatePubRecord();
+ }
+ }
+ }
+
+ void republish( publication_record_type* pRec )
+ {
+ if ( pRec->nState.load( memory_model::memory_order_relaxed ) != active ) {
+ // The record has been excluded from publication list. Reinsert it
+ publish( pRec );
+ }
+ }
+
+ template
+ void try_combining( Container& owner, publication_record_type* pRec )
+ {
+ if ( m_Mutex.try_lock()) {
+ // The thread becomes a combiner
+ lock_guard l( m_Mutex, std::adopt_lock_t());
+
+ // The record pRec can be excluded from publication list. Re-publish it
+ republish( pRec );
+
+ combining( owner );
+ assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
+ }
+ else {
+ // There is another combiner, wait while it executes our request
+ if ( !wait_for_combining( pRec )) {
+ // The thread becomes a combiner
+ lock_guard l( m_Mutex, std::adopt_lock_t());
+
+ // The record pRec can be excluded from publication list. Re-publish it
+ republish( pRec );
+
+ combining( owner );
+ assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
+ }
+ }
+ }
+
+ template
+ void try_batch_combining( Container& owner, publication_record_type * pRec )
+ {
+ if ( m_Mutex.try_lock()) {
+ // The thread becomes a combiner
+ lock_guard l( m_Mutex, std::adopt_lock_t());
+
+ // The record pRec can be excluded from publication list. Re-publish it
+ republish( pRec );
+
+ batch_combining( owner );
+ assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
+ }
+ else {
+ // There is another combiner, wait while it executes our request
+ if ( !wait_for_combining( pRec )) {
+ // The thread becomes a combiner
+ lock_guard l( m_Mutex, std::adopt_lock_t());
+
+ // The record pRec can be excluded from publication list. Re-publish it
+ republish( pRec );
+
+ batch_combining( owner );
+ assert( pRec->op( memory_model::memory_order_relaxed ) == req_Response );
+ }
+ }
+ }
+
+ template
+ void combining( Container& owner )
+ {
+ // The thread is a combiner
+ assert( !m_Mutex.try_lock());
+
+ unsigned int const nCurAge = m_nCount.fetch_add( 1, memory_model::memory_order_relaxed ) + 1;
+
+ unsigned int nEmptyPassCount = 0;
+ unsigned int nUsefulPassCount = 0;
+ for ( unsigned int nPass = 0; nPass < m_nCombinePassCount; ++nPass ) {
+ if ( combining_pass( owner, nCurAge ))
+ ++nUsefulPassCount;
+ else if ( ++nEmptyPassCount > nUsefulPassCount )
+ break;
+ }
+
+ m_Stat.onCombining();
+ if ( ( nCurAge & m_nCompactFactor ) == 0 )
+ compact_list( nCurAge );
+ }
+
+ template
+ bool combining_pass( Container& owner, unsigned int nCurAge )
+ {
+ publication_record* p = m_pHead;
+ bool bOpDone = false;
+ while ( p ) {
+ switch ( p->nState.load( memory_model::memory_order_acquire )) {
+ case active:
+ if ( p->op( memory_model::memory_order_acquire ) >= req_Operation ) {
+ p->nAge.store( nCurAge, memory_model::memory_order_relaxed );
+ owner.fc_apply( static_cast( p ));
+ operation_done( *p );
+ bOpDone = true;
+ }
+ break;
+ case inactive:
+ // Only m_pHead can be inactive in the publication list
+ assert( p == m_pHead );
+ break;
+ case removed:
+ // Such record will be removed on compacting phase
+ break;
+ default:
+ /// ??? That is impossible
+ assert( false );
+ }
+ p = p->pNext.load( memory_model::memory_order_acquire );
+ }
+ return bOpDone;
+ }
+
+ template
+ void batch_combining( Container& owner )
+ {
+ // The thread is a combiner
+ assert( !m_Mutex.try_lock());
+
+ unsigned int const nCurAge = m_nCount.fetch_add( 1, memory_model::memory_order_relaxed ) + 1;
+
+ for ( unsigned int nPass = 0; nPass < m_nCombinePassCount; ++nPass )
+ owner.fc_process( begin(), end());
+
+ combining_pass( owner, nCurAge );
+ m_Stat.onCombining();
+ if ( ( nCurAge & m_nCompactFactor ) == 0 )
+ compact_list( nCurAge );
+ }
+
+ bool wait_for_combining( publication_record_type* pRec )
+ {
+ m_waitStrategy.prepare( *pRec );
+ m_Stat.onPassiveWait();
+
+ while ( pRec->op( memory_model::memory_order_acquire ) != req_Response ) {
+ // The record can be excluded from publication list. Reinsert it
+ republish( pRec );
+
+ m_Stat.onPassiveWaitIteration();
+
+ // Wait while operation processing
+ if ( m_waitStrategy.wait( *this, *pRec ))
+ m_Stat.onWakeupByNotifying();
+
+ if ( m_Mutex.try_lock()) {
+ if ( pRec->op( memory_model::memory_order_acquire ) == req_Response ) {
+ // Operation is done
+ m_Mutex.unlock();
+
+ // Wake up a pending threads
+ m_waitStrategy.wakeup( *this );
+ m_Stat.onPassiveWaitWakeup();
+
+ break;
+ }
+ // The thread becomes a combiner
+ m_Stat.onPassiveToCombiner();
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void compact_list( unsigned int nCurAge )
+ {
+ // Compacts publication list
+ // This function is called only by combiner thread
+
+ try_again:
+ publication_record * pPrev = m_pHead;
+ for ( publication_record * p = pPrev->pNext.load( memory_model::memory_order_acquire ); p; ) {
+ switch ( p->nState.load( memory_model::memory_order_relaxed )) {
+ case active:
+ if ( p->nAge.load( memory_model::memory_order_relaxed ) + m_nCompactFactor < nCurAge )
+ {
+ publication_record * pNext = p->pNext.load( memory_model::memory_order_relaxed );
+ if ( pPrev->pNext.compare_exchange_strong( p, pNext,
+ memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
+ {
+ p->nState.store( inactive, memory_model::memory_order_release );
+ p = pNext;
+ m_Stat.onDeactivatePubRecord();
+ continue;
+ }
+ }
+ break;
+
+ case removed:
+ publication_record * pNext = p->pNext.load( memory_model::memory_order_acquire );
+ if ( cds_likely( pPrev->pNext.compare_exchange_strong( p, pNext, memory_model::memory_order_acquire, atomics::memory_order_relaxed ))) {
+ p = pNext;
+ continue;
+ }
+ else {
+ // CAS can be failed only in beginning of list
+ assert( pPrev == m_pHead );
+ goto try_again;
+ }
+ }
+ pPrev = p;
+ p = p->pNext.load( memory_model::memory_order_acquire );
+ }
+
+ // Iterate over allocated list to find removed records
+ pPrev = m_pAllocatedHead;
+ for ( publication_record * p = pPrev->pNextAllocated.load( memory_model::memory_order_acquire ); p; ) {
+ if ( p->nState.load( memory_model::memory_order_relaxed ) == removed ) {
+ publication_record * pNext = p->pNextAllocated.load( memory_model::memory_order_relaxed );
+ if ( pPrev->pNextAllocated.compare_exchange_strong( p, pNext, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
+ free_publication_record( static_cast( p ));
+ p = pNext;
+ continue;
+ }
+ }
+
+ pPrev = p;
+ p = p->pNextAllocated.load( memory_model::memory_order_relaxed );
+ }
+
+ m_Stat.onCompactPublicationList();
+ }
+ //@endcond
+ };
+
+ //@cond
+ class container
+ {
+ public:
+ template
+ void fc_apply( PubRecord * )
+ {
+ assert( false );
+ }
+
+ template
+ void fc_process( Iterator, Iterator )
+ {
+ assert( false );
+ }
+ };
+ //@endcond
+
+ } // namespace flat_combining
+}} // namespace cds::algo
+
+/*
+ CppMem model (http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/)
+
+ // Combiner thread - slave (waiting) thread
+int main() {
+ atomic_int y = 0; // pRec->op
+ int x = 0; // pRec->data
+ {{{
+ { // slave thread (not combiner)
+ // Op data
+ x = 1;
+ // Annotate request (op)
+ y.store(1, release);
+ // Wait while request done
+ y.load(acquire).readsvalue(2);
+ // Read result
+ r2=x;
+ }
+ |||
+ { // Combiner thread
+ // Read request (op)
+ r1=y.load(acquire).readsvalue(1);
+ // Execute request - change request data
+ x = 2;
+ // store "request processed" flag (pRec->op := req_Response)
+ y.store(2, release);
+ }
+ }}};
+ return 0;
+}
+
+*/
+
+#endif // #ifndef CDSLIB_ALGO_FLAT_COMBINING_KERNEL_H
diff --git a/extern/libcds/cds/algo/flat_combining/wait_strategy.h b/extern/libcds/cds/algo/flat_combining/wait_strategy.h
new file mode 100644
index 0000000000..5d09c49829
--- /dev/null
+++ b/extern/libcds/cds/algo/flat_combining/wait_strategy.h
@@ -0,0 +1,417 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H
+#define CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H
+
+#include
+#include
+#include
+#include
+#include // thread_specific_ptr
+
+
+namespace cds { namespace opt {
+
+ /// Wait strategy option for \p flat_combining::kernel
+ template
+ struct wait_strategy {
+ //@cond
+ template struct pack: public Base
+ {
+ typedef Strategy wait_strategy;
+ };
+ //@endcond
+ };
+
+}} // namespace cds::opt
+
+namespace cds { namespace algo { namespace flat_combining {
+
+ /// Wait strategies for \p flat_combining technique
+ /**
+ Wait strategy specifies how a thread waits until its request is performed by the combiner.
+ See \p wait_strategy::empty wait strategy to explain the interface.
+ */
+ namespace wait_strategy {
+
+ /// Empty wait strategy
+ /**
+ Empty wait strategy is just spinning on request field.
+ All functions are empty.
+ */
+ struct empty
+ {
+ /// Metafunction for defining a publication record for flat combining technique
+ /**
+ Any wait strategy may expand the publication record for storing
+ its own private data.
+ \p PublicationRecord is the type specified by \p flat_combining::kernel.
+ - If the strategy has no thread-private data, it should typedef \p PublicationRecord
+ as a return \p type of metafunction.
+ - Otherwise, if the strategy wants to store anything in thread-local data,
+ it should expand \p PublicationRecord, for example:
+ \code
+ template
+ struct make_publication_record {
+ struct type: public PublicationRecord
+ {
+ int strategy_data;
+ };
+ };
+ \endcode
+ */
+ template
+ struct make_publication_record {
+ typedef PublicationRecord type; ///< Metafunction result
+ };
+
+ /// Prepares the strategy
+ /**
+ This function is called before enter to waiting cycle.
+ Some strategies need to prepare its thread-local data in \p rec.
+
+ \p PublicationRecord is thread's publication record of type \p make_publication_record::type
+ */
+ template
+ void prepare( PublicationRecord& rec )
+ {
+ CDS_UNUSED( rec );
+ }
+
+ /// Waits for the combiner
+ /**
+ The thread calls this function to wait for the combiner process
+ the request.
+ The function returns \p true if the thread was waked up by the combiner,
+ otherwise it should return \p false.
+
+ \p FCKernel is a \p flat_combining::kernel object,
+ \p PublicationRecord is thread's publication record of type \p make_publication_record::type
+ */
+ template
+ bool wait( FCKernel& fc, PublicationRecord& rec )
+ {
+ CDS_UNUSED( fc );
+ CDS_UNUSED( rec );
+ return false;
+ }
+
+ /// Wakes up the thread
+ /**
+ The combiner calls \p %notify() when it has been processed the request.
+
+ \p FCKernel is a \p flat_combining::kernel object,
+ \p PublicationRecord is thread's publication record of type \p make_publication_record::type
+ */
+ template
+ void notify( FCKernel& fc, PublicationRecord& rec )
+ {
+ CDS_UNUSED( fc );
+ CDS_UNUSED( rec );
+ }
+
+ /// Moves control to other thread
+ /**
+ This function is called when the thread becomes the combiner
+ but the request of the thread is already processed.
+ The strategy may call \p fc.wakeup_any() instructs the kernel
+ to wake up any pending thread.
+
+ \p FCKernel is a \p flat_combining::kernel object,
+ */
+ template
+ void wakeup( FCKernel& fc )
+ {
+ CDS_UNUSED( fc );
+ }
+ };
+
+ /// Back-off wait strategy
+ /**
+ Template argument \p Backoff specifies back-off strategy, default is cds::backoff::delay_of<2>
+ */
+ template >
+ struct backoff
+ {
+ typedef BackOff back_off; ///< Back-off strategy
+
+ /// Incorporates back-off strategy into publication record
+ template
+ struct make_publication_record
+ {
+ //@cond
+ struct type: public PublicationRecord
+ {
+ back_off bkoff;
+ };
+ //@endcond
+ };
+
+ /// Resets back-off strategy in \p rec
+ template
+ void prepare( PublicationRecord& rec )
+ {
+ rec.bkoff.reset();
+ }
+
+ /// Calls back-off strategy
+ template
+ bool wait( FCKernel& /*fc*/, PublicationRecord& rec )
+ {
+ rec.bkoff();
+ return false;
+ }
+
+ /// Does nothing
+ template
+ void notify( FCKernel& /*fc*/, PublicationRecord& /*rec*/ )
+ {}
+
+ /// Does nothing
+ template
+ void wakeup( FCKernel& )
+ {}
+ };
+
+ /// Wait strategy based on the single mutex and the condition variable
+ /**
+ The strategy shares the mutex and conditional variable for all thread.
+
+ Template parameter \p Milliseconds specifies waiting duration;
+ the minimal value is 1.
+ */
+ template
+ class single_mutex_single_condvar
+ {
+ //@cond
+ std::mutex m_mutex;
+ std::condition_variable m_condvar;
+ bool m_wakeup;
+
+ typedef std::unique_lock< std::mutex > unique_lock;
+ //@endcond
+
+ public:
+ enum {
+ c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
+ };
+
+ /// Empty metafunction
+ template
+ struct make_publication_record {
+ typedef PublicationRecord type; ///< publication record type
+ };
+
+ /// Default ctor
+ single_mutex_single_condvar()
+ : m_wakeup( false )
+ {}
+
+ /// Does nothing
+ template
+ void prepare( PublicationRecord& /*rec*/ )
+ {}
+
+ /// Sleeps on condition variable waiting for notification from combiner
+ template
+ bool wait( FCKernel& fc, PublicationRecord& rec )
+ {
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ unique_lock lock( m_mutex );
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ if ( m_wakeup ) {
+ m_wakeup = false;
+ return true;
+ }
+
+ bool ret = m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds )) == std::cv_status::no_timeout;
+ m_wakeup = false;
+ return ret;
+ }
+ }
+ return false;
+ }
+
+ /// Calls condition variable function \p notify_all()
+ template
+ void notify( FCKernel& fc, PublicationRecord& /*rec*/ )
+ {
+ wakeup( fc );
+ }
+
+ /// Calls condition variable function \p notify_all()
+ template
+ void wakeup( FCKernel& /*fc*/ )
+ {
+ unique_lock lock( m_mutex );
+ m_wakeup = true;
+ m_condvar.notify_all();
+ }
+ };
+
+ /// Wait strategy based on the single mutex and thread-local condition variables
+ /**
+ The strategy shares the mutex, but each thread has its own conditional variable
+
+ Template parameter \p Milliseconds specifies waiting duration;
+ the minimal value is 1.
+ */
+ template
+ class single_mutex_multi_condvar
+ {
+ //@cond
+ std::mutex m_mutex;
+ bool m_wakeup;
+
+ typedef std::unique_lock< std::mutex > unique_lock;
+ //@endcond
+
+ public:
+ enum {
+ c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
+ };
+
+ /// Incorporates a condition variable into \p PublicationRecord
+ template
+ struct make_publication_record {
+ /// Metafunction result
+ struct type: public PublicationRecord
+ {
+ //@cond
+ std::condition_variable m_condvar;
+ //@endcond
+ };
+ };
+
+ /// Default ctor
+ single_mutex_multi_condvar()
+ : m_wakeup( false )
+ {}
+
+ /// Does nothing
+ template
+ void prepare( PublicationRecord& /*rec*/ )
+ {}
+
+ /// Sleeps on condition variable waiting for notification from combiner
+ template
+ bool wait( FCKernel& fc, PublicationRecord& rec )
+ {
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ unique_lock lock( m_mutex );
+
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ if ( m_wakeup ) {
+ m_wakeup = false;
+ return true;
+ }
+
+ bool ret = rec.m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds )) == std::cv_status::no_timeout;
+ m_wakeup = false;
+ return ret;
+ }
+ }
+ return false;
+ }
+
+ /// Calls condition variable function \p notify_one()
+ template
+ void notify( FCKernel& /*fc*/, PublicationRecord& rec )
+ {
+ unique_lock lock( m_mutex );
+ m_wakeup = true;
+ rec.m_condvar.notify_one();
+ }
+
+ /// Calls \p fc.wakeup_any() to wake up any pending thread
+ template
+ void wakeup( FCKernel& fc )
+ {
+ fc.wakeup_any();
+ }
+ };
+
+ /// Wait strategy where each thread has a mutex and a condition variable
+ /**
+ Template parameter \p Milliseconds specifies waiting duration;
+ the minimal value is 1.
+ */
+ template
+ class multi_mutex_multi_condvar
+ {
+ //@cond
+ typedef std::unique_lock< std::mutex > unique_lock;
+ //@endcond
+ public:
+ enum {
+ c_nWaitMilliseconds = Milliseconds < 1 ? 1 : Milliseconds ///< Waiting duration
+ };
+
+ /// Incorporates a condition variable and a mutex into \p PublicationRecord
+ template
+ struct make_publication_record {
+ /// Metafunction result
+ struct type: public PublicationRecord
+ {
+ //@cond
+ std::mutex m_mutex;
+ std::condition_variable m_condvar;
+ bool m_wakeup;
+
+ type()
+ : m_wakeup( false )
+ {}
+ //@endcond
+ };
+ };
+
+ /// Does nothing
+ template
+ void prepare( PublicationRecord& /*rec*/ )
+ {}
+
+ /// Sleeps on condition variable waiting for notification from combiner
+ template
+ bool wait( FCKernel& fc, PublicationRecord& rec )
+ {
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ unique_lock lock( rec.m_mutex );
+
+ if ( fc.get_operation( rec ) >= req_Operation ) {
+ if ( rec.m_wakeup ) {
+ rec.m_wakeup = false;
+ return true;
+ }
+
+ bool ret = rec.m_condvar.wait_for( lock, std::chrono::milliseconds( c_nWaitMilliseconds )) == std::cv_status::no_timeout;
+ rec.m_wakeup = false;
+ return ret;
+ }
+ }
+ return false;
+ }
+
+ /// Calls condition variable function \p notify_one()
+ template
+ void notify( FCKernel& /*fc*/, PublicationRecord& rec )
+ {
+ unique_lock lock( rec.m_mutex );
+ rec.m_wakeup = true;
+ rec.m_condvar.notify_one();
+ }
+
+ /// Calls \p fc.wakeup_any() to wake up any pending thread
+ template
+ void wakeup( FCKernel& fc )
+ {
+ fc.wakeup_any();
+ }
+ };
+
+ } // namespace wait_strategy
+}}} // namespace cds::algo::flat_combining
+
+#endif //CDSLIB_ALGO_FLAT_COMBINING_WAIT_STRATEGY_H
diff --git a/extern/libcds/cds/algo/int_algo.h b/extern/libcds/cds/algo/int_algo.h
new file mode 100644
index 0000000000..c052cc5e1a
--- /dev/null
+++ b/extern/libcds/cds/algo/int_algo.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_INT_ALGO_H
+#define CDSLIB_INT_ALGO_H
+
+#include
+
+namespace cds { namespace beans {
+ /// Returns largest previous integer for log2( n )
+ static inline size_t log2floor( size_t n )
+ {
+ return n ? cds::bitop::MSBnz( n ) : 0;
+ }
+
+ /// Returns smallest following integer for log2( n )
+ static inline size_t log2ceil( size_t n )
+ {
+ size_t i = log2floor( n );
+ return ( size_t( 1 ) << i ) < n ? i + 1 : i;
+ }
+
+ /// Returns largest previous power of 2 for \p n
+ /**
+ Examples:
+ \code
+ floor2(0) == 1 // !!!
+ floor2(1) == 1
+ floor2(2) == 2
+ floor2(3) == 2
+ floor2(4) == 4
+ floor2(15) == 8
+ floor2(16) == 16
+ floor2(17) == 16
+ \endcode
+ */
+ static inline size_t floor2( size_t n )
+ {
+ return size_t(1) << log2floor( n );
+ }
+
+ /// Returns smallest following power of 2 for \p n
+ /**
+ Examples:
+ \code
+ ceil2(0) == 1 // !!!
+ ceil2(1) == 1
+ ceil2(2) == 2
+ ceil2(3) == 4
+ ceil2(4) == 4
+ ceil2(15) == 16
+ ceil2(16) == 16
+ ceil2(17) == 32
+ \endcode
+ */
+ static inline size_t ceil2( size_t n )
+ {
+ return size_t(1) << log2ceil( n );
+ }
+
+ /// Checks if \p n is power of 2
+ constexpr static inline bool is_power2( size_t n ) noexcept
+ {
+ return (n & (n - 1)) == 0 && n;
+ }
+
+ /// Returns binary logarithm of \p n if \p n is power of two, otherwise returns 0
+ static inline size_t log2( size_t n )
+ {
+ return is_power2(n) ? log2floor(n) : 0;
+ }
+
+#if CDS_BUILD_BITS == 32
+ //@cond
+ // 64bit specializations
+
+/// Returns largest previous integer for log2( n )
+ static inline uint64_t log2floor( uint64_t n )
+ {
+ return n ? cds::bitop::MSBnz( n ) : 0;
+ }
+
+/// Returns smallest following integer for log2( n )
+ static inline uint64_t log2ceil( uint64_t n )
+ {
+ uint64_t i = log2floor( n );
+ return (uint64_t( 1 ) << i) < n ? i + 1 : i;
+ }
+
+/// Returns largest previous power of 2 for \p n
+ /**
+ Examples:
+ \code
+ floor2(0) == 1 // !!!
+ floor2(1) == 1
+ floor2(2) == 2
+ floor2(3) == 2
+ floor2(4) == 4
+ floor2(15) == 8
+ floor2(16) == 16
+ floor2(17) == 16
+ \endcode
+ */
+ static inline uint64_t floor2( uint64_t n )
+ {
+ return uint64_t( 1 ) << log2floor( n );
+ }
+
+/// Returns smallest following power of 2 for \p n
+ /**
+ Examples:
+ \code
+ ceil2(0) == 1 // !!!
+ ceil2(1) == 1
+ ceil2(2) == 2
+ ceil2(3) == 4
+ ceil2(4) == 4
+ ceil2(15) == 16
+ ceil2(16) == 16
+ ceil2(17) == 32
+ \endcode
+ */
+ static inline uint64_t ceil2( uint64_t n )
+ {
+ return uint64_t( 1 ) << log2ceil( n );
+ }
+
+/// Checks if \p n is power of 2
+ constexpr static inline bool is_power2( uint64_t n ) noexcept
+ {
+ return (n & (n - 1)) == 0 && n;
+ }
+
+/// Returns binary logarithm of \p n if \p n is power of two, otherwise returns 0
+ static inline uint64_t log2( uint64_t n )
+ {
+ return is_power2( n ) ? log2floor( n ) : 0;
+ }
+
+ //@endcond
+#endif //#if CDS_BUILD_BITS == 32
+
+}} // namespace cds::beans
+
+#endif // #ifndef CDSLIB_INT_ALGO_H
diff --git a/extern/libcds/cds/algo/split_bitstring.h b/extern/libcds/cds/algo/split_bitstring.h
new file mode 100644
index 0000000000..0f0fd3d281
--- /dev/null
+++ b/extern/libcds/cds/algo/split_bitstring.h
@@ -0,0 +1,445 @@
+// Copyright (c) 2006-2018 Maxim Khizhinsky
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef CDSLIB_ALGO_SPLIT_BITSTRING_H
+#define CDSLIB_ALGO_SPLIT_BITSTRING_H
+
+#include
+
+namespace cds { namespace algo {
+
+ /// Cuts a bit sequence from fixed-size bit-string
+ /**
+ The splitter can be used as an iterator over bit-string.
+ Each call of \p cut() or \p safe_cut() cuts the bit count specified
+ and keeps the position inside bit-string for the next call.
+
+ The splitter stores a const reference to bit-string, not a copy.
+ The maximum count of bits that can be cut in a single call is sizeof(UInt) * 8
+
+ The splitter keeps byte order.
+
+ Template parameters:
+ - \p BitString - a fixed-sized type that interprets as bit string
+ - \p BitStringSize - the size of \p BitString in bytes, default is sizeof( BitString ).
+ You can specify 0 for default.
+ - \p UInt - an unsigned integer, return type for \p cut(), default is \p unsigned
+
+ There are specialized splitters:
+ - a simplified \p byte_splitter algorithm that is suitable when count is multiple of 8.
+ - \p number_splitter algorithm is suitable for a number
+ */
+ template
+ class split_bitstring
+ {
+ public:
+ typedef BitString bitstring; ///< Bit-string type
+ typedef UInt uint_type; ///< Result type of \p cut() function
+ static constexpr size_t const c_bitstring_size = BitStringSize ? BitStringSize : sizeof( BitString ); ///< size of \p BitString in bytes
+
+ //@cond
+ static constexpr unsigned const c_nBitPerByte = 8;
+ //@endcond
+
+ public:
+ /// Initializises the splitter with reference to \p h and zero start bit offset
+ explicit split_bitstring( bitstring const& h )
+ : cur_( reinterpret_cast( &h ))
+ , offset_( 0 )
+ , first_( cur_ )
+ , last_( cur_ + c_bitstring_size )
+ {}
+
+ /// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
+ split_bitstring( bitstring const& h, size_t nBitOffset )
+ : cur_( reinterpret_cast( &h ) + nBitOffset / c_nBitPerByte )
+ , offset_( nBitOffset % c_nBitPerByte )
+ , first_( reinterpret_cast( &h ))
+ , last_( first_ + c_bitstring_size )
+ {}
+
+ /// Returns \p true if end-of-string is not reached yet
+ explicit operator bool() const
+ {
+ return !eos();
+ }
+
+ /// Returns \p true if end-of-stream encountered
+ bool eos() const
+ {
+ return cur_ >= last_;
+ }
+
+ /// Cuts next \p count bits from bit-string
+ /**
+ For performance reason, the function does not manage out-of-bound condition.
+ To control that use \p safe_cut().
+ */
+ uint_type cut( unsigned count )
+ {
+ assert( !eos());
+
+ uint_type result = 0;
+# if defined( CDS_ARCH_LITTLE_ENDIAN )
+ for ( unsigned done = 0; done < count; ) {
+ assert( cur_ < last_ );
+ unsigned bits = count - done;
+ if ( bits > c_nBitPerByte - offset_ )
+ bits = c_nBitPerByte - offset_;
+
+ result |= static_cast(( *cur_ >> offset_ ) & (( 1 << bits ) - 1 )) << done;
+
+ offset_ += bits;
+ assert( offset_ <= c_nBitPerByte );
+ if ( offset_ == c_nBitPerByte ) {
+ offset_ = 0;
+ ++cur_;
+ }
+ done += bits;
+ }
+# else
+ while ( count ) {
+ assert( cur_ < last_ );
+
+ unsigned bits = count <= ( c_nBitPerByte - offset_ ) ? count : c_nBitPerByte - offset_;
+
+ result = ( result << bits ) | (( *cur_ >> offset_ ) & ( ( 1 << bits ) - 1 ));
+
+ offset_ += bits;
+ assert( offset_ <= c_nBitPerByte );
+ if ( offset_ == c_nBitPerByte ) {
+ offset_ = 0;
+ ++cur_;
+ }
+ count -= bits;
+ }
+# endif
+
+ return result;
+ }
+
+ /// Cuts up to \p count from the bit-string
+ /**
+ Safe analog of \p cut() but if \p count is more than the rest of bit-string,
+ only the rest is returned.
+ When \p eos() condition is met the function returns 0.
+ */
+ uint_type safe_cut( unsigned count )
+ {
+ if ( eos())
+ return 0;
+
+ unsigned const rest = static_cast( last_ - cur_ - 1 ) * c_nBitPerByte + ( c_nBitPerByte - offset_ );
+ if ( rest < count )
+ count = rest;
+ return count ? cut( count ) : 0;
+ }
+
+ /// Resets the splitter
+ void reset() noexcept
+ {
+ cur_ = first_;
+ offset_ = 0;
+ }
+
+ /// Returns pointer to source bitstring
+ bitstring const * source() const
+ {
+ return reinterpret_cast( first_ );
+ }
+
+ /// Returns current bit offset from beginning of bit-string
+ size_t bit_offset() const
+ {
+ return offset_ + (cur_ - first_) * c_nBitPerByte;
+ }
+
+ /// Returns how many bits remain
+ size_t rest_count() const
+ {
+ return c_bitstring_size * c_nBitPerByte - bit_offset();
+ }
+
+ /// Returns \p true for any argument
+ static constexpr bool is_correct( unsigned /*count*/ )
+ {
+ return true;
+ }
+
+ private:
+ //@cond
+ uint8_t const* cur_;
+ unsigned offset_;
+ uint8_t const* const first_;
+ uint8_t const* const last_;
+ //@endcond
+ };
+
+ /// Simplified \p split_bitstring algorithm when \p count is multiple of 8
+ template
+ class byte_splitter
+ {
+ public:
+ typedef BitString bitstring; ///< Bit-string type
+ typedef UInt uint_type; ///< Result type of \p cut() function
+ static constexpr size_t const c_bitstring_size = BitStringSize ? BitStringSize : sizeof( BitString ); ///< size of \p BitString in bytes
+
+ //@cond
+ static constexpr unsigned const c_nBitPerByte = 8;
+ //@endcond
+
+ public:
+ /// Initializises the splitter with reference to \p h and zero start bit offset
+ explicit byte_splitter( bitstring const& h )
+ : cur_( reinterpret_cast( &h ))
+ , first_( cur_ )
+ , last_( cur_ + c_bitstring_size )
+ {}
+
+ /// Initializises the splitter with reference to \p h and start bit offset \p nBitOffset
+ byte_splitter( bitstring const& h, size_t nBitOffset )
+ : cur_( reinterpret_cast( &h ) + nBitOffset / c_nBitPerByte )
+ , first_( reinterpret_cast( &h ))
+ , last_( first_ + c_bitstring_size )
+ {
+ assert( is_correct( static_cast( nBitOffset )));
+ assert( !eos());
+ }
+
+ /// Returns \p true if end-of-string is not reached yet
+ explicit operator bool() const
+ {
+ return !eos();
+ }
+
+ /// Returns \p true if end-of-stream encountered
+ bool eos() const
+ {
+ return cur_ >= last_;
+ }
+
+ /// Cuts next \p count bits (must be multiplier of 8) from bit-string
+ /**
+ For performance reason, the function does not manage out-of-bound condition.
+ To control that use \p safe_cut().
+ */
+ uint_type cut( unsigned count )
+ {
+ assert( !eos());
+ assert( is_correct( count ));
+
+ uint_type result = 0;
+
+# if defined( CDS_ARCH_LITTLE_ENDIAN )
+ for ( unsigned i = 0; i < count; i += c_nBitPerByte ) {
+ result |= static_cast( *cur_ ) << i;
+ ++cur_;
+ }
+# else
+ for ( ; count; count -= c_nBitPerByte ) {
+ result = ( result << c_nBitPerByte ) | *cur_;
+ ++cur_;
+ }
+# endif
+
+ return result;
+ }
+
+ /// Cuts up to \p count from the bit-string
+ /**
+ Safe analog of \p cut(): if \p count is more than the rest of bit-string,
+ only the rest is returned.
+ When \p eos() condition is met the function returns 0.
+ */
+ uint_type safe_cut( unsigned count )
+ {
+ if ( eos())
+ return 0;
+
+ unsigned const rest = static_cast( last_ - cur_ - 1 ) * c_nBitPerByte;
+ if ( rest < count )
+ count = rest;
+ return count ? cut( count ) : 0;
+ }
+
+ /// Resets the splitter
+ void reset() noexcept
+ {
+ cur_ = first_;
+ }
+
+ /// Returns pointer to source bitstring
+ bitstring const* source() const
+ {
+ return reinterpret_cast( first_ );
+ }
+
+ /// Returns current bit offset from beginning of bit-string
+ size_t bit_offset() const
+ {
+ return (cur_ - first_) * c_nBitPerByte;
+ }
+
+ /// Returns how many bits remain
+ size_t rest_count() const
+ {
+ return c_bitstring_size * c_nBitPerByte - bit_offset();
+ }
+
+ /// Checks if \p count is multiple of 8
+ static constexpr bool is_correct( unsigned count )
+ {
+ return count % 8 == 0;
+ }
+
+ private:
+ //@cond
+ uint8_t const* cur_;
+ uint8_t const* const first_;
+ uint8_t const* const last_;
+ //@endcond
+ };
+
+
+ /// Cuts a bit sequence from a number
+ /**
+ The splitter can be used as an iterator over bit representation of the number of type \p Int.
+ Each call of \p cut() or \p safe_cut() cuts the bit count specified
+ and keeps the position inside the number for the next call.
+ */
+ template
+ class number_splitter
+ {
+ public:
+ typedef Int int_type; ///< Number type
+ typedef Int uint_type; ///< Result type of \p cut() function
+
+ //@cond
+ static constexpr unsigned const c_nBitPerByte = 8;
+ //@endcond
+
+ public:
+ /// Initalizes the splitter with nymber \p n and initial bit offset 0
+ explicit number_splitter( int_type n )
+ : number_( n )
+ , shift_( 0 )
+ {}
+
+ /// Initalizes the splitter with nymber \p n and initial bit offset \p initial_offset
+ number_splitter( int_type n, size_t initial_offset )
+ : number_( n )
+ , shift_( static_cast( initial_offset ))
+ {
+ assert( initial_offset < sizeof( int_type ) * c_nBitPerByte );
+ }
+
+ /// Returns \p true if end-of-string is not reached yet
+ explicit operator bool() const
+ {
+ return !eos();
+ }
+
+ /// Returns \p true if end-of-stream encountered
+ bool eos() const
+ {
+ return shift_ >= sizeof( int_type ) * c_nBitPerByte;
+ }
+
+ /// Cuts next \p count bits (must be multiplier of 8) from the number
+ /**
+ For performance reason, the function does not manage out-of-bound condition.
+ To control that use \p safe_cut().
+ */
+ int_type cut( unsigned count )
+ {
+ assert( !eos());
+ assert( is_correct( count ));
+
+ int_type result = ( number_ >> shift_ ) & (( 1 << count ) - 1 );
+ shift_ += count;
+
+ return result;
+ }
+
+ /// Cuts up to \p count from the bit-string
+ /**
+ Safe analog of \p cut(): if \p count is more than the rest of \p int_type,
+ only the rest is returned.
+ When \p eos() condition is met the function returns 0.
+ */
+ int_type safe_cut( unsigned count )
+ {
+ if ( eos())
+ return 0;
+
+ unsigned rest = static_cast( rest_count());
+ if ( rest < count )
+ count = rest;
+ return count ? cut( count ) : 0;
+ }
+
+ /// Resets the splitter
+ void reset() noexcept
+ {
+ shift_ = 0;
+ }
+
+ /// Returns initial number
+ int_type source() const
+ {
+ return number_;
+ }
+
+ /// Returns current bit offset from beginning of the number
+ size_t bit_offset() const
+ {
+ return shift_;
+ }
+
+ /// Returns how many bits remain
+ size_t rest_count() const
+ {
+ return sizeof( int_type ) * c_nBitPerByte - shift_;
+ }
+
+ /// Checks if \p count is multiple of 8
+ static constexpr bool is_correct( unsigned count )
+ {
+ return count < sizeof( int_type ) * c_nBitPerByte;
+ }
+
+ private:
+ //@cond
+ int_type const number_;
+ unsigned shift_;
+ //@endcond
+ };
+
+ /// Metafunctin to select a most suitable splitter for type \p BitString of size \p BitStringSize
+ template
+ struct select_splitter
+ {
+ typedef split_bitstring< BitString, BitStringSize > type; ///< metafunction result
+ };
+
+ //@cond
+# define CDS_SELECT_NUMBER_SPLITTER( num_type ) \
+ template <> struct select_splitter { typedef number_splitter