Squashed 'third_party/variant/' content from commit b585021
git-subtree-dir: third_party/variant git-subtree-split: b5850212f16efeb409a112edb1e719d5f5edb604
This commit is contained in:
commit
62e8601919
89
.clang-format
Normal file
89
.clang-format
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
# Mapbox.Variant C/C+ style
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
out
|
||||
profiling
|
||||
build
|
||||
deps
|
||||
*.gcda
|
||||
*.gcno
|
||||
.ycm_extra_conf.pyc
|
127
.travis.yml
Normal file
127
.travis.yml
Normal file
@ -0,0 +1,127 @@
|
||||
language: c
|
||||
|
||||
sudo: false
|
||||
|
||||
# Save common build configurations as shortcuts, so we can reference them later.
|
||||
addons_shortcuts:
|
||||
addons_clang35: &clang35
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5', 'boost-latest' ]
|
||||
packages: [ 'clang-3.5', 'libboost1.55-all-dev' ]
|
||||
addons_clang36: &clang36
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'boost-latest' ]
|
||||
packages: [ 'clang-3.6', 'libboost1.55-all-dev' ]
|
||||
addons_clang37: &clang37
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ]
|
||||
packages: [ 'clang-3.7', 'libboost1.55-all-dev' ]
|
||||
addons_clang38: &clang38
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ]
|
||||
packages: [ 'clang-3.8', 'libboost1.55-all-dev']
|
||||
addons_gcc47: &gcc47
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.7', 'libboost1.55-all-dev' ]
|
||||
addons_gcc48: &gcc48
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.8', 'libboost1.55-all-dev' ]
|
||||
addons_gcc49: &gcc49
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.9', 'libboost1.55-all-dev' ]
|
||||
addons_gcc5: &gcc5
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-5', 'libboost1.55-all-dev' ]
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: osx
|
||||
osx_image: xcode6
|
||||
compiler: clang
|
||||
- os: osx
|
||||
osx_image: xcode7
|
||||
env: TEST_GYP_BUILD=True
|
||||
compiler: clang
|
||||
- os: linux
|
||||
compiler: "clang35"
|
||||
env: CXX=clang++-3.5
|
||||
addons: *clang35
|
||||
- os: linux
|
||||
compiler: "clang36"
|
||||
env: CXX=clang++-3.6
|
||||
addons: *clang36
|
||||
- os: linux
|
||||
compiler: "clang37"
|
||||
env: CXX=clang++-3.7 COVERAGE=True
|
||||
addons: *clang37
|
||||
- os: linux
|
||||
compiler: "clang38"
|
||||
env: CXX=clang++-3.8
|
||||
addons: *clang38
|
||||
- os: linux
|
||||
compiler: "clang38"
|
||||
env: CXX=clang++-3.8 CXX_STD=c++14
|
||||
addons: *clang38
|
||||
- os: linux
|
||||
compiler: "gcc47"
|
||||
env: CXX=g++-4.7
|
||||
addons: *gcc47
|
||||
- os: linux
|
||||
compiler: "gcc48"
|
||||
env: CXX=g++-4.8
|
||||
addons: *gcc48
|
||||
- os: linux
|
||||
compiler: "gcc49"
|
||||
env: CXX=g++-4.9
|
||||
addons: *gcc49
|
||||
- os: linux
|
||||
compiler: "gcc49"
|
||||
env: CXX=g++-4.9 CXX_STD=c++14
|
||||
addons: *gcc49
|
||||
- os: linux
|
||||
compiler: "gcc5"
|
||||
env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
addons: *gcc5
|
||||
- os: linux
|
||||
compiler: "gcc5"
|
||||
env: CXX=g++-5 CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=1"
|
||||
addons: *gcc5
|
||||
|
||||
before_install:
|
||||
- echo ${CXX}
|
||||
- if [[ $(uname -s) == 'Linux' ]]; then
|
||||
export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
|
||||
else
|
||||
brew install boost;
|
||||
export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
|
||||
fi
|
||||
- if [[ ${COVERAGE:-0} == 'True' ]]; then
|
||||
PYTHONUSERBASE=$(pwd)/.local pip install --user cpp-coveralls;
|
||||
fi
|
||||
|
||||
install:
|
||||
- make test
|
||||
- make bench
|
||||
- if [[ $(uname -s) == 'Linux' ]]; then
|
||||
make sizes /usr/include/boost/variant.hpp;
|
||||
else
|
||||
make sizes `brew --prefix`/include/boost/variant.hpp;
|
||||
fi
|
||||
- scripts/run_compilation_failure_tests.sh
|
||||
- if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
|
||||
make clean;
|
||||
make gyp;
|
||||
fi
|
||||
|
||||
script:
|
||||
- if [[ ${COVERAGE:-0} == 'True' ]]; then
|
||||
make clean;
|
||||
make coverage;
|
||||
./out/cov-test;
|
||||
cp unit*gc* test/;
|
||||
./.local/bin/cpp-coveralls -i optional.hpp -i recursive_wrapper.hpp -i variant.hpp -i variant_io.hpp --gcov-options '\-lp';
|
||||
fi
|
40
.ycm_extra_conf.py
Normal file
40
.ycm_extra_conf.py
Normal file
@ -0,0 +1,40 @@
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Configuration for YouCompleteMe Vim plugin
|
||||
#
|
||||
# http://valloric.github.io/YouCompleteMe/
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
from os.path import realpath, dirname
|
||||
|
||||
basedir = dirname(realpath(__file__))
|
||||
|
||||
# some default flags
|
||||
# for more information install clang-3.2-doc package and
|
||||
# check UsersManual.html
|
||||
flags = [
|
||||
'-Werror',
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-pedantic',
|
||||
|
||||
'-std=c++11',
|
||||
|
||||
# '-x' and 'c++' also required
|
||||
# use 'c' for C projects
|
||||
'-x',
|
||||
'c++',
|
||||
|
||||
# include third party libraries
|
||||
'-I.',
|
||||
]
|
||||
|
||||
# youcompleteme is calling this function to get flags
|
||||
# You can also set database for flags. Check: JSONCompilationDatabase.html in
|
||||
# clang-3.2-doc package
|
||||
def FlagsForFile( filename ):
|
||||
return {
|
||||
'flags': flags,
|
||||
'do_cache': True
|
||||
}
|
73
Jamroot
Normal file
73
Jamroot
Normal file
@ -0,0 +1,73 @@
|
||||
# Inofficial and incomplete build file using Boost build system.
|
||||
# You should use make unless you know what you are doing.
|
||||
|
||||
local BOOST_DIR = "/usr/local" ;
|
||||
|
||||
#using clang : : ;
|
||||
|
||||
lib system : : <name>boost_system <search>$(BOOST_DIR)/lib ;
|
||||
lib timer : chrono : <name>boost_timer <search>$(BOOST_DIR)/lib ;
|
||||
lib chrono : system : <name>boost_chrono <search>$(BOOST_DIR)/lib ;
|
||||
|
||||
exe variant-test
|
||||
:
|
||||
test/bench_variant.cpp
|
||||
.//system
|
||||
.//timer
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
#<define>SINGLE_THREADED
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
|
||||
exe binary-visitor-test
|
||||
:
|
||||
test/binary_visitor_test.cpp
|
||||
.//system
|
||||
.//timer
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
exe recursive-wrapper-test
|
||||
:
|
||||
test/recursive_wrapper_test.cpp
|
||||
.//system
|
||||
.//timer
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
exe unique-ptr-test
|
||||
:
|
||||
test/unique_ptr_test.cpp
|
||||
.//system
|
||||
.//timer
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
|
||||
exe reference_wrapper_test
|
||||
:
|
||||
test/reference_wrapper_test.cpp
|
||||
.//system
|
||||
.//timer
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
25
LICENSE
Normal file
25
LICENSE
Normal file
@ -0,0 +1,25 @@
|
||||
Copyright (c) MapBox
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
- Neither the name "MapBox" nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
LICENSE_1_0.txt
Normal file
23
LICENSE_1_0.txt
Normal file
@ -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.
|
110
Makefile
Normal file
110
Makefile
Normal file
@ -0,0 +1,110 @@
|
||||
|
||||
CXX := $(CXX)
|
||||
CXX_STD ?= c++11
|
||||
|
||||
BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
|
||||
RELEASE_FLAGS = -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inlines-hidden
|
||||
DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
|
||||
COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD)
|
||||
CXXFLAGS := $(CXXFLAGS)
|
||||
LDFLAGS := $(LDFLAGS)
|
||||
|
||||
OS:=$(shell uname -s)
|
||||
ifeq ($(OS),Darwin)
|
||||
CXXFLAGS += -stdlib=libc++
|
||||
LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
|
||||
else
|
||||
BOOST_LIBS += -lrt
|
||||
endif
|
||||
|
||||
ifeq (sizes,$(firstword $(MAKECMDGOALS)))
|
||||
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
|
||||
$(eval $(RUN_ARGS):;@:)
|
||||
ifndef RUN_ARGS
|
||||
$(error sizes target requires you pass full path to boost variant.hpp)
|
||||
endif
|
||||
.PHONY: $(RUN_ARGS)
|
||||
endif
|
||||
|
||||
all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
|
||||
|
||||
./deps/gyp:
|
||||
git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
|
||||
|
||||
gyp: ./deps/gyp
|
||||
deps/gyp/gyp --depth=. -Goutput_dir=./ --generator-output=./out -f make
|
||||
make V=1 -C ./out tests
|
||||
./out/Release/tests
|
||||
|
||||
out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
|
||||
out/bench-variant: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
|
||||
out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
|
||||
out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
|
||||
out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp variant_io.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
|
||||
bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
|
||||
./out/bench-variant 100000
|
||||
./out/unique_ptr_test 100000
|
||||
./out/recursive_wrapper_test 100000
|
||||
./out/binary_visitor_test 100000
|
||||
|
||||
out/unit.o: Makefile test/unit.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -c -o $@ test/unit.cpp -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
|
||||
|
||||
out/%.o: test/t/%.cpp Makefile optional.hpp recursive_wrapper.hpp variant.hpp variant_io.hpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -c -o $@ $< -I. -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
|
||||
|
||||
out/unit: out/unit.o out/binary_visitor_1.o out/binary_visitor_2.o out/binary_visitor_3.o out/binary_visitor_4.o out/binary_visitor_5.o out/binary_visitor_6.o out/issue21.o out/mutating_visitor.o out/optional.o out/recursive_wrapper.o out/sizeof.o out/unary_visitor.o out/variant.o
|
||||
mkdir -p ./out
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
test: out/unit
|
||||
./out/unit
|
||||
|
||||
coverage:
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/cov-test --coverage test/unit.cpp test/t/*.cpp -I./ -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
sizes: Makefile variant.hpp recursive_wrapper.hpp
|
||||
mkdir -p ./out
|
||||
@$(CXX) -o ./out/our_variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world.out
|
||||
@$(CXX) -o ./out/boost_variant_hello_world.out $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world.out
|
||||
@$(CXX) -o ./out/our_variant_hello_world ./test/our_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world
|
||||
@$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world
|
||||
|
||||
profile: out/bench-variant-debug
|
||||
mkdir -p profiling/
|
||||
rm -rf profiling/*
|
||||
iprofiler -timeprofiler -d profiling/ ./out/bench-variant-debug 500000
|
||||
|
||||
clean:
|
||||
rm -rf ./out
|
||||
rm -rf *.dSYM
|
||||
rm -f unit.gc*
|
||||
rm -f *gcov
|
||||
rm -f test/unit.gc*
|
||||
rm -f test/*gcov
|
||||
rm -f *.gcda *.gcno
|
||||
|
||||
pgo: out Makefile variant.hpp recursive_wrapper.hpp
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
|
||||
./test-variant 500000 >/dev/null 2>/dev/null
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
|
||||
|
||||
.PHONY: sizes test
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
||||
# Mapbox Variant
|
||||
|
||||
An alternative to `boost::variant` for C++11.
|
||||
|
||||
[](https://travis-ci.org/mapbox/variant)
|
||||
[](https://ci.appveyor.com/project/Mapbox/variant)
|
||||
[](https://coveralls.io/r/mapbox/variant?branch=master)
|
||||
|
||||
|
||||
## Why use Mapbox Variant?
|
||||
|
||||
Mapbox variant has the same speedy performance of `boost::variant` but is
|
||||
faster to compile, results in smaller binaries, and has no dependencies.
|
||||
|
||||
For example on OS X 10.9 with clang++ and libc++:
|
||||
|
||||
Test | Mapbox Variant | Boost Variant
|
||||
---- | -------------- | -------------
|
||||
Size of pre-compiled header (release / debug) | 2.8/2.8 MB | 12/15 MB
|
||||
Size of simple program linking variant (release / debug) | 8/24 K | 12/40 K
|
||||
Time to compile header | 185 ms | 675 ms
|
||||
|
||||
(Numbers from an older version of Mapbox variant.)
|
||||
|
||||
|
||||
## Goals
|
||||
|
||||
Mapbox `variant` has been a very valuable, lightweight alternative for apps
|
||||
that can use c++11 or c++14 but that do not want a boost dependency.
|
||||
Mapbox `variant` has also been useful in apps that do depend on boost, like
|
||||
mapnik, to help (slightly) with compile times and to majorly lessen dependence
|
||||
on boost in core headers. The original goal and near term goal is to maintain
|
||||
external API compatibility with `boost::variant` such that Mapbox `variant`
|
||||
can be a "drop in". At the same time the goal is to stay minimal: Only
|
||||
implement the features that are actually needed in existing software. So being
|
||||
an "incomplete" implementation is just fine.
|
||||
|
||||
Currently Mapbox variant doesn't try to be API compatible with the upcoming
|
||||
variant standard, because the standard is not finished and it would be too much
|
||||
work. But we'll revisit this decision in the future if needed.
|
||||
|
||||
If Mapbox variant is not for you, have a look at [these other
|
||||
implementations](doc/other_implementations.md).
|
||||
|
||||
Want to know more about the upcoming standard? Have a look at our
|
||||
[overview](doc/standards_effort.md).
|
||||
|
||||
|
||||
## Depends
|
||||
|
||||
- Compiler supporting `-std=c++11` or `-std=c++14`
|
||||
|
||||
Tested with:
|
||||
|
||||
- g++-4.7
|
||||
- g++-4.8
|
||||
- g++-4.9
|
||||
- g++-5
|
||||
- clang++-3.5
|
||||
- clang++-3.6
|
||||
- clang++-3.7
|
||||
- clang++-3.8
|
||||
- Visual Studio 2015
|
||||
|
||||
## Usage
|
||||
|
||||
There is nothing to build, just include `variant.hpp` and
|
||||
`recursive_wrapper.hpp` in your project. Include `variant_io.hpp` if you need
|
||||
the `operator<<` overload for variant.
|
||||
|
||||
|
||||
## Unit Tests
|
||||
|
||||
On Unix systems compile and run the unit tests with `make test`.
|
||||
|
||||
On Windows run `scripts/build-local.bat`.
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
* The `variant` can not hold references (something like `variant<int&>` is
|
||||
not possible). You might want to try `std::reference_wrapper` instead.
|
||||
|
||||
|
||||
## Deprecations
|
||||
|
||||
* The included implementation of `optional` is deprecated and will be removed
|
||||
in a future version. See https://github.com/mapbox/variant/issues/64.
|
||||
* Old versions of the code needed visitors to derive from `static_visitor`.
|
||||
This is not needed any more and marked as deprecated. The `static_visitor`
|
||||
class will be removed in future versions.
|
||||
|
||||
|
||||
## Benchmarks
|
||||
|
||||
The benchmarks depend on:
|
||||
|
||||
- Boost headers (for benchmarking against `boost::variant`)
|
||||
- Boost built with `--with-timer` (used for benchmark timing)
|
||||
|
||||
On Unix systems set your boost includes and libs locations and run `make test`:
|
||||
|
||||
export LDFLAGS='-L/opt/boost/lib'
|
||||
export CXXFLAGS='-I/opt/boost/include'
|
||||
make bench
|
||||
|
||||
|
||||
## Check object sizes
|
||||
|
||||
make sizes /path/to/boost/variant.hpp
|
||||
|
17
appveyor.yml
Normal file
17
appveyor.yml
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
platform:
|
||||
- x64
|
||||
- x86
|
||||
|
||||
configuration:
|
||||
- Debug
|
||||
- Release
|
||||
|
||||
os: Visual Studio 2015
|
||||
|
||||
install:
|
||||
- CALL scripts\build-appveyor.bat
|
||||
|
||||
build: off
|
||||
test: off
|
||||
deploy: off
|
143
common.gypi
Normal file
143
common.gypi
Normal file
@ -0,0 +1,143 @@
|
||||
{
|
||||
"conditions": [
|
||||
["OS=='win'", {
|
||||
"target_defaults": {
|
||||
"default_configuration": "Release_x64",
|
||||
"msbuild_toolset":"v140",
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"ExceptionHandling": 1, # /EHsc
|
||||
"RuntimeTypeInfo": "true" # /GR
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"Debug_Win32": {
|
||||
"msvs_configuration_platform": "Win32",
|
||||
"defines": [ "DEBUG","_DEBUG"],
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"RuntimeLibrary": "1", # static debug /MTd
|
||||
"Optimization": 0, # /Od, no optimization
|
||||
"MinimalRebuild": "false",
|
||||
"OmitFramePointers": "false",
|
||||
"BasicRuntimeChecks": 3 # /RTC1
|
||||
}
|
||||
}
|
||||
},
|
||||
"Debug_x64": {
|
||||
"msvs_configuration_platform": "x64",
|
||||
"defines": [ "DEBUG","_DEBUG"],
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"RuntimeLibrary": "1", # static debug /MTd
|
||||
"Optimization": 0, # /Od, no optimization
|
||||
"MinimalRebuild": "false",
|
||||
"OmitFramePointers": "false",
|
||||
"BasicRuntimeChecks": 3 # /RTC1
|
||||
}
|
||||
}
|
||||
},
|
||||
"Release_Win32": {
|
||||
"msvs_configuration_platform": "Win32",
|
||||
"defines": [ "NDEBUG"],
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"RuntimeLibrary": 0, # static release
|
||||
"Optimization": 3, # /Ox, full optimization
|
||||
"FavorSizeOrSpeed": 1, # /Ot, favour speed over size
|
||||
"InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
|
||||
"WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
|
||||
"OmitFramePointers": "true",
|
||||
"EnableFunctionLevelLinking": "true",
|
||||
"EnableIntrinsicFunctions": "true",
|
||||
"AdditionalOptions": [
|
||||
"/MP", # compile across multiple CPUs
|
||||
],
|
||||
"DebugInformationFormat": "0"
|
||||
},
|
||||
"VCLibrarianTool": {
|
||||
"AdditionalOptions": [
|
||||
"/LTCG" # link time code generation
|
||||
],
|
||||
},
|
||||
"VCLinkerTool": {
|
||||
"LinkTimeCodeGeneration": 1, # link-time code generation
|
||||
"OptimizeReferences": 2, # /OPT:REF
|
||||
"EnableCOMDATFolding": 2, # /OPT:ICF
|
||||
"LinkIncremental": 1, # disable incremental linking
|
||||
"GenerateDebugInformation": "false"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Release_x64": {
|
||||
"msvs_configuration_platform": "x64",
|
||||
"defines": [ "NDEBUG"],
|
||||
"msvs_settings": {
|
||||
"VCCLCompilerTool": {
|
||||
"RuntimeLibrary": 0, # static release
|
||||
"Optimization": 3, # /Ox, full optimization
|
||||
"FavorSizeOrSpeed": 1, # /Ot, favour speed over size
|
||||
"InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
|
||||
"WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
|
||||
"OmitFramePointers": "true",
|
||||
"EnableFunctionLevelLinking": "true",
|
||||
"EnableIntrinsicFunctions": "true",
|
||||
"AdditionalOptions": [
|
||||
"/MP", # compile across multiple CPUs
|
||||
],
|
||||
"DebugInformationFormat": "0"
|
||||
},
|
||||
"VCLibrarianTool": {
|
||||
"AdditionalOptions": [
|
||||
"/LTCG" # link time code generation
|
||||
],
|
||||
},
|
||||
"VCLinkerTool": {
|
||||
"LinkTimeCodeGeneration": 1, # link-time code generation
|
||||
"OptimizeReferences": 2, # /OPT:REF
|
||||
"EnableCOMDATFolding": 2, # /OPT:ICF
|
||||
"LinkIncremental": 1, # disable incremental linking
|
||||
"GenerateDebugInformation": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"target_defaults": {
|
||||
"default_configuration": "Release",
|
||||
"xcode_settings": {
|
||||
"CLANG_CXX_LIBRARY": "libc++",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD":"c++11",
|
||||
"GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
|
||||
},
|
||||
"cflags_cc": ["-std=c++11"],
|
||||
"configurations": {
|
||||
"Debug": {
|
||||
"defines": [
|
||||
"DEBUG"
|
||||
],
|
||||
"xcode_settings": {
|
||||
"GCC_OPTIMIZATION_LEVEL": "0",
|
||||
"GCC_GENERATE_DEBUGGING_SYMBOLS": "YES",
|
||||
"OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ]
|
||||
}
|
||||
},
|
||||
"Release": {
|
||||
"defines": [
|
||||
"NDEBUG"
|
||||
],
|
||||
"xcode_settings": {
|
||||
"GCC_OPTIMIZATION_LEVEL": "3",
|
||||
"GCC_GENERATE_DEBUGGING_SYMBOLS": "NO",
|
||||
"DEAD_CODE_STRIPPING": "YES",
|
||||
"GCC_INLINES_ARE_PRIVATE_EXTERN": "YES",
|
||||
"OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-O3" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
|
15
doc/other_implementations.md
Normal file
15
doc/other_implementations.md
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
# Other implementations of variant and optional
|
||||
|
||||
These are some other implementations of `variant` and/or `optional` types.
|
||||
They are not necessarily compatible with this implementation. This is an
|
||||
incomplete list.
|
||||
|
||||
* [Boost Variant](http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html) and [Boost Optional](http://www.boost.org/doc/libs/1_59_0/libs/optional/doc/html/index.html)
|
||||
* [Eggs Variant](http://eggs-cpp.github.io/variant/) by [Agustín Bergé](http://talesofcpp.fusionfenix.com/)
|
||||
* [anthonyw/variant](https://bitbucket.org/anthonyw/variant) (implementation of P0110R0)
|
||||
* [JasonL9000/cppcon14](https://github.com/JasonL9000/cppcon14)
|
||||
* [tomilov/variant](https://github.com/tomilov/variant)
|
||||
* [akrzemi1/Optional](https://github.com/akrzemi1/Optional)
|
||||
* [mpark/variant](https://github.com/mpark/variant)
|
||||
|
28
doc/standards_effort.md
Normal file
28
doc/standards_effort.md
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
# Standards efforts
|
||||
|
||||
A `variant` type is on planned for inclusion in the C++ Standard, probably in
|
||||
C++17. Current working papers are (list extracted from [2015 working group
|
||||
papers](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/)):
|
||||
|
||||
* 2015-09-28: Variant design review. [P0086R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0086r0.pdf)
|
||||
* 2015-09-28: Variant: a type-safe union without undefined behavior (v2) [P0087R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0087r0.pdf)
|
||||
* 2015-09-27: Variant: a type-safe union that is rarely invalid (v5) [P0088R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0088r0.pdf)
|
||||
* 2015-09-24: Simply a Strong Variant [P0093R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0093r0.html)
|
||||
* 2015-09-24: Simply a Basic Variant [P0094R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0094r0.html)
|
||||
* 2015-09-24: The Case for a Language Based Variant [P0096R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0095r0.html)
|
||||
* 2015-09-25: Implementing the strong guarantee for variant<> assignment [P0110R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0110r0.html)
|
||||
* 2015-09-24: Homogeneous interface for variant, any and optional (Revision 1) [P0032R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0032r1.pdf)
|
||||
|
||||
Last state can be seen from
|
||||
[The Variant Saga: A happy ending?](https://isocpp.org/blog/2015/11/the-variant-saga-a-happy-ending).
|
||||
|
||||
The `optional` type is also on the way into the standard. The papers are:
|
||||
* 2013-10-03: A proposal to add a utility class to represent optional objects (Revision 5) [N3793](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3793.html)
|
||||
* 2014-01-18: Working Draft, Technical Specification on C++ Extensions for Library Fundamentals [N3848](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3848.html)
|
||||
|
||||
## Older Papers
|
||||
|
||||
* Older working drafts are: N4218 (rev 1), N4516 (rev 2), N4450 (rev 3), and [N4542](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4542.pdf) (rev 4). They have been split into P0086 (general design discussions) and P0087 and P0088 (containing two competing? specs).
|
||||
* 2015-07-28: Variant: Discriminated Union with Value Semantics [P0080R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0080r0.pdf) An alternative proposal to N4542.
|
||||
|
74
optional.hpp
Normal file
74
optional.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
|
||||
#define MAPBOX_UTIL_OPTIONAL_HPP
|
||||
|
||||
#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
|
||||
template <typename T>
|
||||
class optional
|
||||
{
|
||||
static_assert(!std::is_reference<T>::value, "optional doesn't support references");
|
||||
|
||||
struct none_type
|
||||
{
|
||||
};
|
||||
|
||||
variant<none_type, T> variant_;
|
||||
|
||||
public:
|
||||
optional() = default;
|
||||
|
||||
optional(optional const& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{ // protect against invalid self-assignment
|
||||
variant_ = rhs.variant_;
|
||||
}
|
||||
}
|
||||
|
||||
optional(T const& v) { variant_ = v; }
|
||||
|
||||
explicit operator bool() const noexcept { return variant_.template is<T>(); }
|
||||
|
||||
T const& get() const { return variant_.template get<T>(); }
|
||||
T& get() { return variant_.template get<T>(); }
|
||||
|
||||
T const& operator*() const { return this->get(); }
|
||||
T operator*() { return this->get(); }
|
||||
|
||||
optional& operator=(T const& v)
|
||||
{
|
||||
variant_ = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
optional& operator=(optional const& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
variant_ = rhs.variant_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void emplace(Args&&... args)
|
||||
{
|
||||
variant_ = T{std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
void reset() { variant_ = none_type{}; }
|
||||
|
||||
}; // class optional
|
||||
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_OPTIONAL_HPP
|
122
recursive_wrapper.hpp
Normal file
122
recursive_wrapper.hpp
Normal file
@ -0,0 +1,122 @@
|
||||
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
||||
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
||||
|
||||
// Based on variant/recursive_wrapper.hpp from boost.
|
||||
//
|
||||
// Original license:
|
||||
//
|
||||
// Copyright (c) 2002-2003
|
||||
// Eric Friedman, Itay Maman
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
|
||||
template <typename T>
|
||||
class recursive_wrapper
|
||||
{
|
||||
|
||||
T* p_;
|
||||
|
||||
void assign(T const& rhs)
|
||||
{
|
||||
this->get() = rhs;
|
||||
}
|
||||
|
||||
public:
|
||||
using type = T;
|
||||
|
||||
/**
|
||||
* Default constructor default initializes the internally stored value.
|
||||
* For POD types this means nothing is done and the storage is
|
||||
* uninitialized.
|
||||
*
|
||||
* @throws std::bad_alloc if there is insufficient memory for an object
|
||||
* of type T.
|
||||
* @throws any exception thrown by the default constructur of T.
|
||||
*/
|
||||
recursive_wrapper()
|
||||
: p_(new T){};
|
||||
|
||||
~recursive_wrapper() noexcept { delete p_; };
|
||||
|
||||
recursive_wrapper(recursive_wrapper const& operand)
|
||||
: p_(new T(operand.get())) {}
|
||||
|
||||
recursive_wrapper(T const& operand)
|
||||
: p_(new T(operand)) {}
|
||||
|
||||
recursive_wrapper(recursive_wrapper&& operand)
|
||||
: p_(new T(std::move(operand.get()))) {}
|
||||
|
||||
recursive_wrapper(T&& operand)
|
||||
: p_(new T(std::move(operand))) {}
|
||||
|
||||
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
|
||||
{
|
||||
assign(rhs.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline recursive_wrapper& operator=(T const& rhs)
|
||||
{
|
||||
assign(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(recursive_wrapper& operand) noexcept
|
||||
{
|
||||
T* temp = operand.p_;
|
||||
operand.p_ = p_;
|
||||
p_ = temp;
|
||||
}
|
||||
|
||||
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
|
||||
{
|
||||
swap(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
recursive_wrapper& operator=(T&& rhs)
|
||||
{
|
||||
get() = std::move(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
assert(p_);
|
||||
return *get_pointer();
|
||||
}
|
||||
|
||||
T const& get() const
|
||||
{
|
||||
assert(p_);
|
||||
return *get_pointer();
|
||||
}
|
||||
|
||||
T* get_pointer() { return p_; }
|
||||
|
||||
const T* get_pointer() const { return p_; }
|
||||
|
||||
operator T const&() const { return this->get(); }
|
||||
|
||||
operator T&() { return this->get(); }
|
||||
|
||||
}; // class recursive_wrapper
|
||||
|
||||
template <typename T>
|
||||
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
32
scripts/build-appveyor.bat
Normal file
32
scripts/build-appveyor.bat
Normal file
@ -0,0 +1,32 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL
|
||||
|
||||
SET PATH=c:\python27;%PATH%
|
||||
|
||||
ECHO activating VS command prompt
|
||||
IF /I "%PLATFORM"=="x64" (
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
|
||||
) ELSE (
|
||||
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
|
||||
)
|
||||
|
||||
IF NOT EXIST deps\gyp git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
|
||||
|
||||
CALL deps\gyp\gyp.bat variant.gyp --depth=. ^
|
||||
-f msvs ^
|
||||
-G msvs_version=2015 ^
|
||||
--generator-output=build
|
||||
|
||||
SET MSBUILD_PLATFORM=%platform%
|
||||
IF /I "%MSBUILD_PLATFORM%" == "x86" SET MSBUILD_PLATFORM=Win32
|
||||
|
||||
|
||||
msbuild ^
|
||||
build\variant.sln ^
|
||||
/nologo ^
|
||||
/toolsversion:14.0 ^
|
||||
/p:PlatformToolset=v140 ^
|
||||
/p:Configuration=%configuration% ^
|
||||
/p:Platform=%MSBUILD_PLATFORM%
|
||||
|
||||
build\"%configuration%"\tests.exe
|
7
scripts/build-local.bat
Normal file
7
scripts/build-local.bat
Normal file
@ -0,0 +1,7 @@
|
||||
@ECHO OFF
|
||||
SETLOCAL
|
||||
|
||||
SET platform=x64
|
||||
SET configuration=Release
|
||||
|
||||
CALL scripts\build-appveyor.bat
|
50
scripts/run_compilation_failure_tests.sh
Executable file
50
scripts/run_compilation_failure_tests.sh
Executable file
@ -0,0 +1,50 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Try to compile all programs in the test/compilation_failure directory.
|
||||
# Compilation must fail and the error message must match the pattern in the
|
||||
# corresponding .pattern file.
|
||||
#
|
||||
|
||||
DIR="test/compilation_failure"
|
||||
CXX=${CXX:-clang++}
|
||||
|
||||
if [ `uname -s` = "Darwin" ]; then
|
||||
CXXFLAGS="$CXXFLAGS -stdlib=libc++"
|
||||
fi
|
||||
|
||||
error_msg() {
|
||||
if [ ! -z "$1" ]; then
|
||||
printf 'output was:\n=======\n%s\n=======\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
exit_code=0
|
||||
for test_code in $DIR/*.cpp; do
|
||||
name=`basename $test_code .cpp`
|
||||
|
||||
result=`${CXX} -std=c++11 -c -o /dev/null -I. ${CXXFLAGS} ${test_code} 2>&1`
|
||||
status=$?
|
||||
|
||||
if [ $status = 1 ]; then
|
||||
expected=`sed -n -e '/@EXPECTED/s/.*: \+//p' ${test_code}`
|
||||
if echo $result | grep -q "$expected"; then
|
||||
echo "$name [OK]"
|
||||
else
|
||||
echo "$name [FAILED - wrong error message]"
|
||||
echo "Expected error message: $expected"
|
||||
error_msg "$result"
|
||||
exit_code=1
|
||||
fi
|
||||
elif [ $status = 0 ]; then
|
||||
echo "$name [FAILED - compile was successful]"
|
||||
error_msg "$result"
|
||||
exit_code=1
|
||||
else
|
||||
echo "$name [FAILED - unknown error in compile]"
|
||||
error_msg "$result"
|
||||
exit_code=1
|
||||
fi
|
||||
done
|
||||
|
||||
exit ${exit_code}
|
||||
|
185
test/bench_variant.cpp
Normal file
185
test/bench_variant.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define TEXT_SHORT "Test"
|
||||
#define TEXT_LONG "Testing various variant implementations with a longish string ........................................."
|
||||
#define NUM_SAMPLES 3
|
||||
//#define BOOST_VARIANT_MINIMIZE_SIZE
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
namespace test {
|
||||
|
||||
template <typename V>
|
||||
struct Holder
|
||||
{
|
||||
typedef V value_type;
|
||||
std::vector<value_type> data;
|
||||
|
||||
template <typename T>
|
||||
void append_move(T&& obj)
|
||||
{
|
||||
data.emplace_back(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void append(T const& obj)
|
||||
{
|
||||
data.push_back(obj);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
struct print
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
std::cerr << val << ":" << typeid(T).name() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct dummy : boost::static_visitor<>
|
||||
{
|
||||
dummy(V& v)
|
||||
: v_(v) {}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T&& val) const
|
||||
{
|
||||
v_ = std::move(val);
|
||||
}
|
||||
V& v_;
|
||||
};
|
||||
|
||||
template <typename V>
|
||||
struct dummy2
|
||||
{
|
||||
dummy2(V& v)
|
||||
: v_(v) {}
|
||||
|
||||
template <typename T>
|
||||
void operator()(T&& val) const
|
||||
{
|
||||
v_ = std::move(val);
|
||||
}
|
||||
V& v_;
|
||||
};
|
||||
|
||||
void run_boost_test(std::size_t runs)
|
||||
{
|
||||
test::Holder<boost::variant<int, double, std::string>> h;
|
||||
h.data.reserve(runs);
|
||||
for (std::size_t i = 0; i < runs; ++i)
|
||||
{
|
||||
h.append_move(std::string(TEXT_SHORT));
|
||||
h.append_move(std::string(TEXT_LONG));
|
||||
h.append_move(123);
|
||||
h.append_move(3.14159);
|
||||
}
|
||||
|
||||
boost::variant<int, double, std::string> v;
|
||||
for (auto const& v2 : h.data)
|
||||
{
|
||||
dummy<boost::variant<int, double, std::string>> d(v);
|
||||
boost::apply_visitor(d, v2);
|
||||
}
|
||||
}
|
||||
|
||||
void run_variant_test(std::size_t runs)
|
||||
{
|
||||
test::Holder<util::variant<int, double, std::string>> h;
|
||||
h.data.reserve(runs);
|
||||
for (std::size_t i = 0; i < runs; ++i)
|
||||
{
|
||||
h.append_move(std::string(TEXT_SHORT));
|
||||
h.append_move(std::string(TEXT_LONG));
|
||||
h.append_move(123);
|
||||
h.append_move(3.14159);
|
||||
}
|
||||
|
||||
util::variant<int, double, std::string> v;
|
||||
for (auto const& v2 : h.data)
|
||||
{
|
||||
dummy2<util::variant<int, double, std::string>> d(v);
|
||||
util::apply_visitor(d, v2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef SINGLE_THREADED
|
||||
const std::size_t THREADS = 4;
|
||||
#endif
|
||||
const std::size_t NUM_RUNS = static_cast<std::size_t>(std::stol(argv[1]));
|
||||
|
||||
#ifdef SINGLE_THREADED
|
||||
|
||||
for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
|
||||
{
|
||||
|
||||
{
|
||||
std::cerr << "custom variant: ";
|
||||
boost::timer::auto_cpu_timer t;
|
||||
run_variant_test(NUM_RUNS);
|
||||
}
|
||||
{
|
||||
std::cerr << "boost variant: ";
|
||||
boost::timer::auto_cpu_timer t;
|
||||
run_boost_test(NUM_RUNS);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
|
||||
{
|
||||
{
|
||||
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
|
||||
typedef thread_group::value_type value_type;
|
||||
thread_group tg;
|
||||
std::cerr << "custom variant: ";
|
||||
boost::timer::auto_cpu_timer timer;
|
||||
for (std::size_t i = 0; i < THREADS; ++i)
|
||||
{
|
||||
tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
|
||||
}
|
||||
std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
|
||||
}
|
||||
|
||||
{
|
||||
typedef std::vector<std::unique_ptr<std::thread>> thread_group;
|
||||
typedef thread_group::value_type value_type;
|
||||
thread_group tg;
|
||||
std::cerr << "boost variant: ";
|
||||
boost::timer::auto_cpu_timer timer;
|
||||
for (std::size_t i = 0; i < THREADS; ++i)
|
||||
{
|
||||
tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
|
||||
}
|
||||
std::for_each(tg.begin(), tg.end(), [](value_type& t) {if (t->joinable()) t->join(); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
138
test/binary_visitor_test.cpp
Normal file
138
test/binary_visitor_test.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
namespace test {
|
||||
|
||||
template <typename T>
|
||||
struct string_to_number
|
||||
{
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_to_number<double>
|
||||
{
|
||||
double operator()(std::string const& str) const
|
||||
{
|
||||
return std::stod(str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_to_number<std::int64_t>
|
||||
{
|
||||
std::int64_t operator()(std::string const& str) const
|
||||
{
|
||||
return std::stoll(str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_to_number<std::uint64_t>
|
||||
{
|
||||
std::uint64_t operator()(std::string const& str) const
|
||||
{
|
||||
return std::stoull(str);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_to_number<bool>
|
||||
{
|
||||
bool operator()(std::string const& str) const
|
||||
{
|
||||
bool result;
|
||||
std::istringstream(str) >> std::boolalpha >> result;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct javascript_equal_visitor
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(T lhs, T rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||
bool operator()(T lhs, std::string const& rhs) const
|
||||
{
|
||||
return lhs == string_to_number<T>()(rhs);
|
||||
}
|
||||
|
||||
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
|
||||
bool operator()(std::string const& lhs, T rhs) const
|
||||
{
|
||||
return string_to_number<T>()(lhs) == rhs;
|
||||
}
|
||||
|
||||
template <typename T0, typename T1>
|
||||
bool operator()(T0 lhs, T1 rhs) const
|
||||
{
|
||||
return lhs == static_cast<T0>(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct javascript_equal
|
||||
{
|
||||
javascript_equal(T const& lhs)
|
||||
: lhs_(lhs) {}
|
||||
|
||||
bool operator()(T const& rhs) const
|
||||
{
|
||||
return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
|
||||
}
|
||||
T const& lhs_;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
|
||||
variant_type v0(3.14159);
|
||||
variant_type v1(std::string("3.14159"));
|
||||
variant_type v2(std::uint64_t(1));
|
||||
|
||||
std::cerr << v0 << " == " << v1 << " -> "
|
||||
<< std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
|
||||
|
||||
std::vector<variant_type> vec;
|
||||
|
||||
vec.emplace_back(std::string("1"));
|
||||
vec.push_back(variant_type(std::uint64_t(2)));
|
||||
vec.push_back(variant_type(std::uint64_t(3)));
|
||||
vec.push_back(std::string("3.14159"));
|
||||
vec.emplace_back(3.14159);
|
||||
|
||||
//auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
|
||||
// return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
|
||||
// });
|
||||
|
||||
auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
|
||||
|
||||
if (itr != std::end(vec))
|
||||
{
|
||||
std::cout << "found " << *itr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "can't find " << v2 << '\n';
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
20
test/boost_variant_hello_world.cpp
Normal file
20
test/boost_variant_hello_world.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
struct check : boost::static_visitor<>
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
if (val != 0) throw std::runtime_error("invalid");
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef boost::variant<bool, int, double> variant_type;
|
||||
variant_type v(0);
|
||||
boost::apply_visitor(check(), v);
|
||||
return 0;
|
||||
}
|
22
test/compilation_failure/default_constructor.cpp
Normal file
22
test/compilation_failure/default_constructor.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
// @EXPECTED: First type in variant must be default constructible to allow default construction of variant
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
// Checks that the first type in a variant must be default constructible to
|
||||
// make the variant default constructible.
|
||||
|
||||
struct no_def_constructor
|
||||
{
|
||||
|
||||
int value;
|
||||
|
||||
no_def_constructor() = delete;
|
||||
|
||||
no_def_constructor(int v) : value(v) {}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<no_def_constructor> x;
|
||||
}
|
11
test/compilation_failure/empty_typelist.cpp
Normal file
11
test/compilation_failure/empty_typelist.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
// @EXPECTED: Template parameter type list of variant can not be empty
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
// Empty type list should not work.
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<> x;
|
||||
}
|
11
test/compilation_failure/equality.cpp
Normal file
11
test/compilation_failure/equality.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
// @EXPECTED:
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<int> x;
|
||||
mapbox::util::variant<double> y;
|
||||
x == y;
|
||||
}
|
10
test/compilation_failure/get_type.cpp
Normal file
10
test/compilation_failure/get_type.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
// @EXPECTED: enable_if
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<int, double> x;
|
||||
x.get<std::string>();
|
||||
}
|
10
test/compilation_failure/is_type.cpp
Normal file
10
test/compilation_failure/is_type.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
// @EXPECTED: invalid type in T in `is<T>()` for this variant
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<int, double> x;
|
||||
x.is<std::string>();
|
||||
}
|
24
test/compilation_failure/mutating_visitor_on_const.cpp
Normal file
24
test/compilation_failure/mutating_visitor_on_const.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
// @EXPECTED: const int
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
struct mutating_visitor
|
||||
{
|
||||
mutating_visitor(int val)
|
||||
: val_(val) {}
|
||||
|
||||
void operator()(int& val) const
|
||||
{
|
||||
val = val_;
|
||||
}
|
||||
|
||||
int val_;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
const mapbox::util::variant<int> var(123);
|
||||
const mutating_visitor visitor(456);
|
||||
mapbox::util::apply_visitor(visitor, var);
|
||||
}
|
9
test/compilation_failure/no-reference.cpp
Normal file
9
test/compilation_failure/no-reference.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
// @EXPECTED: Variant can not hold reference types
|
||||
|
||||
#include <variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
mapbox::util::variant<double, int&, long> x{mapbox::util::no_init()};
|
||||
}
|
11613
test/include/catch.hpp
Normal file
11613
test/include/catch.hpp
Normal file
File diff suppressed because it is too large
Load Diff
20
test/our_variant_hello_world.cpp
Normal file
20
test/our_variant_hello_world.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "variant.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
struct check
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
if (val != 0) throw std::runtime_error("invalid");
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
typedef mapbox::util::variant<bool, int, double> variant_type;
|
||||
variant_type v(0);
|
||||
mapbox::util::apply_visitor(check(), v);
|
||||
return 0;
|
||||
}
|
125
test/recursive_wrapper_test.cpp
Normal file
125
test/recursive_wrapper_test.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
namespace test {
|
||||
|
||||
struct add;
|
||||
struct sub;
|
||||
|
||||
template <typename OpTag>
|
||||
struct binary_op;
|
||||
|
||||
typedef util::variant<int,
|
||||
util::recursive_wrapper<binary_op<add>>,
|
||||
util::recursive_wrapper<binary_op<sub>>>
|
||||
expression;
|
||||
|
||||
template <typename Op>
|
||||
struct binary_op
|
||||
{
|
||||
expression left; // variant instantiated here...
|
||||
expression right;
|
||||
|
||||
binary_op(expression&& lhs, expression&& rhs)
|
||||
: left(std::move(lhs)), right(std::move(rhs))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct print
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
std::cerr << val << ":" << typeid(T).name() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct test
|
||||
{
|
||||
template <typename T>
|
||||
std::string operator()(T const& obj) const
|
||||
{
|
||||
return std::string("TYPE_ID=") + typeid(obj).name();
|
||||
}
|
||||
};
|
||||
|
||||
struct calculator
|
||||
{
|
||||
public:
|
||||
int operator()(int value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
int operator()(binary_op<add> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(calculator(), binary.left) + util::apply_visitor(calculator(), binary.right);
|
||||
}
|
||||
|
||||
int operator()(binary_op<sub> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(calculator(), binary.left) - util::apply_visitor(calculator(), binary.right);
|
||||
}
|
||||
};
|
||||
|
||||
struct to_string
|
||||
{
|
||||
public:
|
||||
std::string operator()(int value) const
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::string operator()(binary_op<add> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(to_string(), binary.left) + std::string("+") + util::apply_visitor(to_string(), binary.right);
|
||||
}
|
||||
|
||||
std::string operator()(binary_op<sub> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(to_string(), binary.left) + std::string("-") + util::apply_visitor(to_string(), binary.right);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
|
||||
|
||||
test::expression sum(test::binary_op<test::add>(2, 3));
|
||||
test::expression result(test::binary_op<test::sub>(std::move(sum), 4));
|
||||
|
||||
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
|
||||
|
||||
int total = 0;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
for (std::size_t i = 0; i < NUM_ITER; ++i)
|
||||
{
|
||||
total += util::apply_visitor(test::calculator(), result);
|
||||
}
|
||||
}
|
||||
std::cerr << "total=" << total << std::endl;
|
||||
|
||||
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
76
test/reference_wrapper_test.cpp
Normal file
76
test/reference_wrapper_test.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
namespace test {
|
||||
|
||||
struct point
|
||||
{
|
||||
public:
|
||||
point(double x_, double y_)
|
||||
: x(x_), y(y_) {}
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
struct line_string : std::vector<point>
|
||||
{
|
||||
};
|
||||
struct polygon : std::vector<line_string>
|
||||
{
|
||||
};
|
||||
using variant = util::variant<std::reference_wrapper<const point>,
|
||||
std::reference_wrapper<const line_string>,
|
||||
std::reference_wrapper<const polygon>>;
|
||||
|
||||
struct print
|
||||
{
|
||||
using result_type = void;
|
||||
void operator()(point const& pt) const
|
||||
{
|
||||
std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
|
||||
}
|
||||
void operator()(line_string const& line) const
|
||||
{
|
||||
std::cerr << "Line(";
|
||||
for (auto const& pt : line)
|
||||
{
|
||||
std::cerr << pt.x << " " << pt.y << ",";
|
||||
}
|
||||
std::cerr << ")" << std::endl;
|
||||
}
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
std::cerr << typeid(T).name() << std::endl;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << sizeof(test::polygon) << std::endl;
|
||||
std::cerr << sizeof(test::variant) << std::endl;
|
||||
test::point pt(123, 456);
|
||||
test::variant var = std::cref(pt);
|
||||
util::apply_visitor(test::print(), var);
|
||||
test::line_string line;
|
||||
line.push_back(pt);
|
||||
line.push_back(pt);
|
||||
line.push_back(test::point(999, 333));
|
||||
var = std::cref(line);
|
||||
util::apply_visitor(test::print(), var);
|
||||
std::cerr << "Is line (cref) ? " << var.is<std::reference_wrapper<test::line_string const>>() << std::endl;
|
||||
auto const& line2 = var.get<test::line_string>(); // accessing underlying type of std::reference_wrapper<T>
|
||||
test::print printer;
|
||||
printer(line2);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
7
test/t/binary_visitor_1.cpp
Normal file
7
test/t/binary_visitor_1.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " i-d"
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
7
test/t/binary_visitor_2.cpp
Normal file
7
test/t/binary_visitor_2.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " b-i-d"
|
||||
using variant_type = mapbox::util::variant<bool, int, double>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
7
test/t/binary_visitor_3.cpp
Normal file
7
test/t/binary_visitor_3.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " i-d-b"
|
||||
using variant_type = mapbox::util::variant<int, double, bool>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
7
test/t/binary_visitor_4.cpp
Normal file
7
test/t/binary_visitor_4.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " b-i-d-c"
|
||||
using variant_type = mapbox::util::variant<bool, int, double, char>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
7
test/t/binary_visitor_5.cpp
Normal file
7
test/t/binary_visitor_5.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " b-i-c-d-i"
|
||||
using variant_type = mapbox::util::variant<bool, int, char, double, int>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
7
test/t/binary_visitor_6.cpp
Normal file
7
test/t/binary_visitor_6.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
#define NAME_EXT " b-i-i-d-c-u"
|
||||
using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;
|
||||
|
||||
#include "binary_visitor_impl.hpp"
|
204
test/t/binary_visitor_impl.hpp
Normal file
204
test/t/binary_visitor_impl.hpp
Normal file
@ -0,0 +1,204 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant_io.hpp"
|
||||
|
||||
struct add_visitor
|
||||
{
|
||||
add_visitor() {}
|
||||
|
||||
template <typename A, typename B>
|
||||
double operator()(A a, B b) const
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
const variant_type a{7};
|
||||
const variant_type b = 3;
|
||||
const variant_type c{7.1};
|
||||
const variant_type d = 2.9;
|
||||
|
||||
const add_visitor v;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
|
||||
}
|
||||
|
||||
TEST_CASE("non-const binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
const variant_type a = 7;
|
||||
const variant_type b = 3;
|
||||
const variant_type c = 7.1;
|
||||
const variant_type d = 2.9;
|
||||
|
||||
add_visitor v;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
|
||||
}
|
||||
|
||||
TEST_CASE("const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
variant_type a = 7;
|
||||
variant_type b = 3;
|
||||
variant_type c = 7.1;
|
||||
variant_type d = 2.9;
|
||||
|
||||
const add_visitor v;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
|
||||
}
|
||||
|
||||
TEST_CASE("non-const binary visitor works on non-const variants" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
variant_type a = 7;
|
||||
variant_type b = 3;
|
||||
variant_type c = 7.1;
|
||||
variant_type d = 2.9;
|
||||
|
||||
add_visitor v;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(9.9));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(9.9));
|
||||
}
|
||||
|
||||
TEST_CASE("rvalue binary visitor works on const variants" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
const variant_type a = 7;
|
||||
const variant_type b = 3;
|
||||
const variant_type c = 7.1;
|
||||
const variant_type d = 2.9;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, b) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, d) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, c) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, a, d) == Approx(9.9));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, b, a) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, c) == Approx(10));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, c, a) == Approx(14.1));
|
||||
REQUIRE(mapbox::util::apply_visitor(add_visitor{}, d, a) == Approx(9.9));
|
||||
}
|
||||
|
||||
struct sum_mul_visitor
|
||||
{
|
||||
double sum;
|
||||
|
||||
sum_mul_visitor() : sum(0.0) {}
|
||||
|
||||
template <typename A, typename B>
|
||||
double operator()(A a, B b)
|
||||
{
|
||||
double m = a * b;
|
||||
sum += m;
|
||||
return m;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("mutable binary visitor works" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
const variant_type a = 2;
|
||||
const variant_type b = 3;
|
||||
const variant_type c = 0.1;
|
||||
const variant_type d = 0.2;
|
||||
|
||||
sum_mul_visitor v;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, b) == Approx(6));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, d) == Approx(0.02));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, c) == Approx(0.2));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, a, d) == Approx(0.4));
|
||||
|
||||
REQUIRE(v.sum == Approx(6.62));
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(v, b, a) == Approx(6));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, c) == Approx(0.02));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, c, a) == Approx(0.2));
|
||||
REQUIRE(mapbox::util::apply_visitor(v, d, a) == Approx(0.4));
|
||||
}
|
||||
|
||||
struct swap_visitor
|
||||
{
|
||||
swap_visitor(){};
|
||||
|
||||
template <typename A, typename B>
|
||||
void operator()(A& a, B& b) const
|
||||
{
|
||||
using T = typename std::common_type<A, B>::type;
|
||||
T tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("static mutating visitor on mutable variants works" NAME_EXT, "[visitor][binary visitor]")
|
||||
{
|
||||
variant_type a = 2;
|
||||
variant_type b = 3;
|
||||
variant_type c = 0.1;
|
||||
variant_type d = 0.2;
|
||||
|
||||
const swap_visitor v;
|
||||
|
||||
SECTION("swap a and b")
|
||||
{
|
||||
mapbox::util::apply_visitor(v, a, b);
|
||||
REQUIRE(a.get<int>() == 3);
|
||||
REQUIRE(b.get<int>() == 2);
|
||||
}
|
||||
|
||||
SECTION("swap c and d")
|
||||
{
|
||||
mapbox::util::apply_visitor(v, c, d);
|
||||
REQUIRE(c.get<double>() == Approx(0.2));
|
||||
REQUIRE(d.get<double>() == Approx(0.1));
|
||||
}
|
||||
|
||||
SECTION("swap a and c")
|
||||
{
|
||||
mapbox::util::apply_visitor(v, a, c);
|
||||
REQUIRE(a.get<int>() == 0);
|
||||
REQUIRE(c.get<double>() == Approx(2.0));
|
||||
}
|
||||
|
||||
SECTION("swap c and a")
|
||||
{
|
||||
mapbox::util::apply_visitor(v, c, a);
|
||||
REQUIRE(a.get<int>() == 0);
|
||||
REQUIRE(c.get<double>() == Approx(2.0));
|
||||
}
|
||||
}
|
48
test/t/issue21.cpp
Normal file
48
test/t/issue21.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
// https://github.com/mapbox/variant/issues/21
|
||||
|
||||
static int count;
|
||||
|
||||
struct t1
|
||||
{
|
||||
int value;
|
||||
t1(int v) : value(v)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
~t1()
|
||||
{
|
||||
--count;
|
||||
}
|
||||
};
|
||||
|
||||
struct t2
|
||||
{
|
||||
int value;
|
||||
t2(int v) : value(v)
|
||||
{ // constructor fails
|
||||
throw std::runtime_error("fail");
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
|
||||
{
|
||||
|
||||
using variant_type = mapbox::util::variant<t1, t2>;
|
||||
|
||||
count = 0;
|
||||
{
|
||||
variant_type v{42};
|
||||
REQUIRE(v.is<t1>());
|
||||
REQUIRE(v.get<t1>().value == 42);
|
||||
REQUIRE_THROWS({
|
||||
v.set<t2>(13);
|
||||
});
|
||||
}
|
||||
REQUIRE(count == 0);
|
||||
}
|
36
test/t/mutating_visitor.cpp
Normal file
36
test/t/mutating_visitor.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
template <typename T>
|
||||
struct mutating_visitor
|
||||
{
|
||||
mutating_visitor(T& val)
|
||||
: val_(val) {}
|
||||
|
||||
void operator()(T& val) const
|
||||
{
|
||||
val = val_;
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
void operator()(T1&) const
|
||||
{
|
||||
} // no-op
|
||||
|
||||
T& val_;
|
||||
};
|
||||
|
||||
TEST_CASE("variant visitation", "[visitor][unary visitor]")
|
||||
{
|
||||
mapbox::util::variant<int, double, std::string> var(123);
|
||||
REQUIRE(var.get<int>() == 123);
|
||||
int val = 456;
|
||||
const mutating_visitor<int> visitor(val);
|
||||
mapbox::util::apply_visitor(visitor, var);
|
||||
REQUIRE(var.get<int>() == 456);
|
||||
}
|
102
test/t/optional.cpp
Normal file
102
test/t/optional.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "optional.hpp"
|
||||
|
||||
struct dummy
|
||||
{
|
||||
dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
|
||||
int m_1;
|
||||
int m_2;
|
||||
};
|
||||
|
||||
TEST_CASE("optional can be instantiated with a POD type", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<int> dbl_opt;
|
||||
|
||||
REQUIRE(!dbl_opt);
|
||||
dbl_opt = 3;
|
||||
REQUIRE(dbl_opt);
|
||||
|
||||
REQUIRE(dbl_opt.get() == 3);
|
||||
REQUIRE(*dbl_opt == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("copy c'tor", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<int> dbl_opt;
|
||||
|
||||
REQUIRE(!dbl_opt);
|
||||
dbl_opt = 3;
|
||||
REQUIRE(dbl_opt);
|
||||
|
||||
mapbox::util::optional<int> other = dbl_opt;
|
||||
|
||||
REQUIRE(other.get() == 3);
|
||||
REQUIRE(*other == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("const operator*, const get()", "[optional]")
|
||||
{
|
||||
const mapbox::util::optional<int> dbl_opt = 3;
|
||||
|
||||
REQUIRE(dbl_opt);
|
||||
|
||||
auto pi1 = dbl_opt.get();
|
||||
auto pi2 = *dbl_opt;
|
||||
|
||||
REQUIRE(pi1 == 3);
|
||||
REQUIRE(pi2 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("non-const operator*, non-const get()", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<int> dbl_opt = 3;
|
||||
|
||||
REQUIRE(dbl_opt);
|
||||
|
||||
auto pi1 = dbl_opt.get();
|
||||
auto pi2 = *dbl_opt;
|
||||
|
||||
REQUIRE(pi1 == 3);
|
||||
REQUIRE(pi2 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("emplace initialization, reset", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<dummy> dummy_opt;
|
||||
REQUIRE(!dummy_opt);
|
||||
|
||||
// rvalues, baby!
|
||||
dummy_opt.emplace(1, 2);
|
||||
REQUIRE(dummy_opt);
|
||||
REQUIRE(dummy_opt.get().m_1 == 1);
|
||||
REQUIRE((*dummy_opt).m_2 == 2);
|
||||
|
||||
dummy_opt.reset();
|
||||
REQUIRE(!dummy_opt);
|
||||
}
|
||||
|
||||
TEST_CASE("assignment", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<int> a;
|
||||
mapbox::util::optional<int> b;
|
||||
|
||||
a = 1;
|
||||
b = 3;
|
||||
REQUIRE(a.get() == 1);
|
||||
REQUIRE(b.get() == 3);
|
||||
b = a;
|
||||
REQUIRE(a.get() == b.get());
|
||||
REQUIRE(b.get() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("self assignment", "[optional]")
|
||||
{
|
||||
mapbox::util::optional<int> a;
|
||||
|
||||
a = 1;
|
||||
REQUIRE(a.get() == 1);
|
||||
a = a;
|
||||
REQUIRE(a.get() == 1);
|
||||
}
|
158
test/t/recursive_wrapper.cpp
Normal file
158
test/t/recursive_wrapper.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "recursive_wrapper.hpp"
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using rwi = mapbox::util::recursive_wrapper<int>;
|
||||
using rwp = mapbox::util::recursive_wrapper<std::pair<int, int>>;
|
||||
|
||||
static_assert(std::is_same<rwi::type, int>::value, "type check failed");
|
||||
|
||||
TEST_CASE("recursive wrapper of int")
|
||||
{
|
||||
|
||||
SECTION("construct with value")
|
||||
{
|
||||
rwi a{7};
|
||||
|
||||
REQUIRE(a.get() == 7);
|
||||
REQUIRE(*a.get_pointer() == 7);
|
||||
|
||||
a = 8;
|
||||
REQUIRE(a.get() == 8);
|
||||
|
||||
rwi b{a};
|
||||
REQUIRE(b.get() == 8);
|
||||
|
||||
rwi c;
|
||||
c = b;
|
||||
REQUIRE(b.get() == 8);
|
||||
REQUIRE(c.get() == 8);
|
||||
|
||||
c = 9;
|
||||
REQUIRE(c.get() == 9);
|
||||
|
||||
int x = 10;
|
||||
c = x;
|
||||
REQUIRE(c.get() == 10);
|
||||
|
||||
b = std::move(c);
|
||||
REQUIRE(b.get() == 10);
|
||||
}
|
||||
|
||||
SECTION("construct with const reference")
|
||||
{
|
||||
int i = 7;
|
||||
rwi a{i};
|
||||
|
||||
REQUIRE(a.get() == 7);
|
||||
}
|
||||
|
||||
SECTION("implicit conversion to reference of underlying type")
|
||||
{
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
rwi const a{7};
|
||||
REQUIRE(a.get() == 7);
|
||||
REQUIRE(*a.get_pointer() == 7);
|
||||
|
||||
rwi::type const& underlying = a;
|
||||
REQUIRE(underlying == 7);
|
||||
}
|
||||
|
||||
SECTION("non const")
|
||||
{
|
||||
rwi a{7};
|
||||
REQUIRE(a.get() == 7);
|
||||
REQUIRE(*a.get_pointer() == 7);
|
||||
|
||||
rwi::type& underlying = a;
|
||||
REQUIRE(underlying == 7);
|
||||
a = 8;
|
||||
REQUIRE(underlying == 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("move of recursive wrapper")
|
||||
{
|
||||
rwi a{1};
|
||||
|
||||
SECTION("move constructor")
|
||||
{
|
||||
rwi b{std::move(a)};
|
||||
REQUIRE(b.get() == 1);
|
||||
}
|
||||
|
||||
SECTION("operator= on rvalue")
|
||||
{
|
||||
rwi b{2};
|
||||
b = std::move(a);
|
||||
REQUIRE(b.get() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("swap")
|
||||
{
|
||||
rwi a{1};
|
||||
rwi b{2};
|
||||
|
||||
REQUIRE(a.get() == 1);
|
||||
REQUIRE(b.get() == 2);
|
||||
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
|
||||
REQUIRE(a.get() == 2);
|
||||
REQUIRE(b.get() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("recursive wrapper of pair<int, int>")
|
||||
{
|
||||
|
||||
SECTION("default constructed")
|
||||
{
|
||||
rwp a;
|
||||
REQUIRE(a.get().first == 0);
|
||||
REQUIRE(a.get().second == 0);
|
||||
}
|
||||
|
||||
SECTION("construct with value")
|
||||
{
|
||||
rwp a{std::make_pair(1, 2)};
|
||||
|
||||
REQUIRE(a.get().first == 1);
|
||||
REQUIRE(a.get().second == 2);
|
||||
|
||||
REQUIRE(a.get_pointer()->first == 1);
|
||||
REQUIRE(a.get_pointer()->second == 2);
|
||||
|
||||
a = {3, 4};
|
||||
REQUIRE(a.get().first == 3);
|
||||
REQUIRE(a.get().second == 4);
|
||||
|
||||
rwp b{a};
|
||||
REQUIRE(b.get().first == 3);
|
||||
REQUIRE(b.get().second == 4);
|
||||
|
||||
rwp c;
|
||||
c = b;
|
||||
REQUIRE(b.get().first == 3);
|
||||
REQUIRE(b.get().second == 4);
|
||||
REQUIRE(c.get().first == 3);
|
||||
REQUIRE(c.get().second == 4);
|
||||
|
||||
c = {5, 6};
|
||||
REQUIRE(c.get().first == 5);
|
||||
REQUIRE(c.get().second == 6);
|
||||
|
||||
b = std::move(c);
|
||||
REQUIRE(b.get().first == 5);
|
||||
REQUIRE(b.get().second == 6);
|
||||
// REQUIRE(c.get_pointer() == nullptr);
|
||||
}
|
||||
}
|
52
test/t/sizeof.cpp
Normal file
52
test/t/sizeof.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
struct some_struct
|
||||
{
|
||||
int a;
|
||||
bool b;
|
||||
std::string c;
|
||||
};
|
||||
|
||||
using variant_internal_index_type = size_t;
|
||||
|
||||
TEST_CASE("size of variants")
|
||||
{
|
||||
constexpr const auto min_overhead = sizeof(variant_internal_index_type);
|
||||
|
||||
using namespace std; // workaround for bug in GCC <= 4.8 where max_align_t is not in std
|
||||
constexpr const auto max_overhead = alignof(max_align_t) + min_overhead;
|
||||
|
||||
using v1 = mapbox::util::variant<int>;
|
||||
using v2 = mapbox::util::variant<int, bool, int64_t>;
|
||||
using v3 = mapbox::util::variant<int, std::string>;
|
||||
using v4 = mapbox::util::variant<std::string, std::string>;
|
||||
using v5 = mapbox::util::variant<some_struct>;
|
||||
|
||||
constexpr const auto si = sizeof(int);
|
||||
constexpr const auto sb = sizeof(bool);
|
||||
constexpr const auto si64 = sizeof(int64_t);
|
||||
constexpr const auto sd = sizeof(double);
|
||||
constexpr const auto sstr = sizeof(std::string);
|
||||
constexpr const auto spi = sizeof(std::pair<int, int>);
|
||||
constexpr const auto ss = sizeof(some_struct);
|
||||
|
||||
REQUIRE(sizeof(v1) <= max_overhead + si);
|
||||
REQUIRE(sizeof(v2) <= max_overhead + std::max({si, sb, si64}));
|
||||
REQUIRE(sizeof(v3) <= max_overhead + std::max({si, sstr}));
|
||||
REQUIRE(sizeof(v4) <= max_overhead + sstr);
|
||||
REQUIRE(sizeof(v5) <= max_overhead + ss);
|
||||
|
||||
REQUIRE(sizeof(v1) >= min_overhead + si);
|
||||
REQUIRE(sizeof(v2) >= min_overhead + std::max({si, sb, si64}));
|
||||
REQUIRE(sizeof(v3) >= min_overhead + std::max({si, sstr}));
|
||||
REQUIRE(sizeof(v4) >= min_overhead + sstr);
|
||||
REQUIRE(sizeof(v5) >= min_overhead + ss);
|
||||
}
|
127
test/t/unary_visitor.cpp
Normal file
127
test/t/unary_visitor.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
struct some_visitor
|
||||
{
|
||||
int var_;
|
||||
|
||||
some_visitor(int init)
|
||||
: var_(init) {}
|
||||
|
||||
int operator()(int val) const
|
||||
{
|
||||
return var_ + val;
|
||||
}
|
||||
|
||||
int operator()(double val) const
|
||||
{
|
||||
return var_ + int(val);
|
||||
}
|
||||
|
||||
int operator()(const std::string&) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("non-const visitor works on const variants", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = const mapbox::util::variant<int, double, std::string>;
|
||||
variant_type var1(123);
|
||||
variant_type var2(3.2);
|
||||
variant_type var3("foo");
|
||||
REQUIRE(var1.get<int>() == 123);
|
||||
REQUIRE(var2.get<double>() == Approx(3.2));
|
||||
REQUIRE(var3.get<std::string>() == "foo");
|
||||
|
||||
some_visitor visitor{1};
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("const visitor works on const variants", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = const mapbox::util::variant<int, double, std::string>;
|
||||
variant_type var1(123);
|
||||
variant_type var2(3.2);
|
||||
variant_type var3("foo");
|
||||
REQUIRE(var1.get<int>() == 123);
|
||||
REQUIRE(var2.get<double>() == Approx(3.2));
|
||||
REQUIRE(var3.get<std::string>() == "foo");
|
||||
|
||||
const some_visitor visitor{1};
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var1) == 124);
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var2) == 4);
|
||||
REQUIRE(mapbox::util::apply_visitor(visitor, var3) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("rvalue visitor works on const variants", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = const mapbox::util::variant<int, double, std::string>;
|
||||
variant_type var1(123);
|
||||
variant_type var2(3.2);
|
||||
variant_type var3("foo");
|
||||
REQUIRE(var1.get<int>() == 123);
|
||||
REQUIRE(var2.get<double>() == Approx(3.2));
|
||||
REQUIRE(var3.get<std::string>() == "foo");
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var1) == 124);
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var2) == 4);
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, var3) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("visitor works on rvalue variants", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = const mapbox::util::variant<int, double, std::string>;
|
||||
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{123}) == 124);
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{3.2}) == 4);
|
||||
REQUIRE(mapbox::util::apply_visitor(some_visitor{1}, variant_type{"foo"}) == 0);
|
||||
}
|
||||
|
||||
struct total_sizeof
|
||||
{
|
||||
total_sizeof() : total_(0) {}
|
||||
|
||||
template <class Value>
|
||||
int operator()(const Value&) const
|
||||
{
|
||||
total_ += int(sizeof(Value));
|
||||
return total_;
|
||||
}
|
||||
|
||||
int result() const
|
||||
{
|
||||
return total_;
|
||||
}
|
||||
|
||||
mutable int total_;
|
||||
|
||||
}; // total_sizeof
|
||||
|
||||
TEST_CASE("changes in visitor should be visible", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, std::string, double>;
|
||||
variant_type v;
|
||||
total_sizeof ts;
|
||||
v = 5.9;
|
||||
REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(double));
|
||||
REQUIRE(ts.result() == sizeof(double));
|
||||
}
|
||||
|
||||
TEST_CASE("changes in const visitor (with mutable internals) should be visible", "[visitor][unary visitor]")
|
||||
{
|
||||
using variant_type = const mapbox::util::variant<int, std::string, double>;
|
||||
variant_type v{"foo"};
|
||||
const total_sizeof ts;
|
||||
REQUIRE(mapbox::util::apply_visitor(ts, v) == sizeof(std::string));
|
||||
REQUIRE(ts.result() == sizeof(std::string));
|
||||
}
|
570
test/t/variant.cpp
Normal file
570
test/t/variant.cpp
Normal file
@ -0,0 +1,570 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// Hack to make nullptr work with Catch
|
||||
namespace std {
|
||||
|
||||
template <class C, class T>
|
||||
std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, std::nullptr_t)
|
||||
{
|
||||
return os << (void*)nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("variant can be moved into vector", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<bool, std::string>;
|
||||
variant_type v(std::string("test"));
|
||||
std::vector<variant_type> vec;
|
||||
vec.emplace_back(std::move(v));
|
||||
REQUIRE(v.get<std::string>() != std::string("test"));
|
||||
REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
|
||||
}
|
||||
|
||||
TEST_CASE("variant should support built-in types", "[variant]")
|
||||
{
|
||||
SECTION("bool")
|
||||
{
|
||||
mapbox::util::variant<bool> v(true);
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<bool>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<bool>() == true);
|
||||
v.set<bool>(false);
|
||||
REQUIRE(v.get<bool>() == false);
|
||||
v = true;
|
||||
REQUIRE(v == mapbox::util::variant<bool>(true));
|
||||
}
|
||||
SECTION("nullptr")
|
||||
{
|
||||
using value_type = std::nullptr_t;
|
||||
mapbox::util::variant<value_type> v(nullptr);
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == nullptr);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(nullptr));
|
||||
}
|
||||
SECTION("unique_ptr")
|
||||
{
|
||||
using value_type = std::unique_ptr<std::string>;
|
||||
mapbox::util::variant<value_type> v(value_type(new std::string("hello")));
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
|
||||
REQUIRE(*v.get<value_type>() == "hello");
|
||||
}
|
||||
SECTION("string")
|
||||
{
|
||||
using value_type = std::string;
|
||||
mapbox::util::variant<value_type> v(value_type("hello"));
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == value_type("hello"));
|
||||
v.set<value_type>(value_type("there"));
|
||||
REQUIRE(v.get<value_type>() == value_type("there"));
|
||||
v = value_type("variant");
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type("variant")));
|
||||
}
|
||||
SECTION("size_t")
|
||||
{
|
||||
using value_type = std::size_t;
|
||||
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
|
||||
v.set<value_type>(value_type(0));
|
||||
REQUIRE(v.get<value_type>() == value_type(0));
|
||||
v = value_type(1);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
|
||||
}
|
||||
SECTION("int8_t")
|
||||
{
|
||||
using value_type = std::int8_t;
|
||||
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
|
||||
v.set<value_type>(0);
|
||||
REQUIRE(v.get<value_type>() == value_type(0));
|
||||
v = value_type(1);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
|
||||
}
|
||||
SECTION("int16_t")
|
||||
{
|
||||
using value_type = std::int16_t;
|
||||
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
|
||||
v.set<value_type>(0);
|
||||
REQUIRE(v.get<value_type>() == value_type(0));
|
||||
v = value_type(1);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
|
||||
}
|
||||
SECTION("int32_t")
|
||||
{
|
||||
using value_type = std::int32_t;
|
||||
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
|
||||
v.set<value_type>(0);
|
||||
REQUIRE(v.get<value_type>() == value_type(0));
|
||||
v = value_type(1);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
|
||||
}
|
||||
SECTION("int64_t")
|
||||
{
|
||||
using value_type = std::int64_t;
|
||||
mapbox::util::variant<value_type> v(std::numeric_limits<value_type>::max());
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<value_type>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
|
||||
v.set<value_type>(0);
|
||||
REQUIRE(v.get<value_type>() == value_type(0));
|
||||
v = value_type(1);
|
||||
REQUIRE(v == mapbox::util::variant<value_type>(value_type(1)));
|
||||
}
|
||||
}
|
||||
|
||||
struct MissionInteger
|
||||
{
|
||||
using value_type = uint64_t;
|
||||
value_type val_;
|
||||
|
||||
public:
|
||||
MissionInteger(uint64_t val) : val_(val) {}
|
||||
|
||||
bool operator==(MissionInteger const& rhs) const
|
||||
{
|
||||
return (val_ == rhs.get());
|
||||
}
|
||||
|
||||
uint64_t get() const
|
||||
{
|
||||
return val_;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
|
||||
{
|
||||
os << rhs.get();
|
||||
return os;
|
||||
}
|
||||
|
||||
TEST_CASE("variant should support custom types", "[variant]")
|
||||
{
|
||||
// http://www.missionintegers.com/integer/34838300
|
||||
mapbox::util::variant<MissionInteger> v(MissionInteger(34838300));
|
||||
REQUIRE(v.valid());
|
||||
REQUIRE(v.is<MissionInteger>());
|
||||
REQUIRE(v.which() == 0);
|
||||
REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
|
||||
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
|
||||
// TODO: should both of the set usages below compile?
|
||||
v.set<MissionInteger>(MissionInteger::value_type(0));
|
||||
v.set<MissionInteger>(MissionInteger(0));
|
||||
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
|
||||
v = MissionInteger(1);
|
||||
REQUIRE(v == mapbox::util::variant<MissionInteger>(MissionInteger(1)));
|
||||
}
|
||||
|
||||
TEST_CASE("variant::which() returns zero based index of stored type", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<bool, std::string, std::uint64_t, std::int64_t, double, float>;
|
||||
// which() returns index in forward order
|
||||
REQUIRE(0 == variant_type(true).which());
|
||||
REQUIRE(1 == variant_type(std::string("test")).which());
|
||||
REQUIRE(2 == variant_type(std::uint64_t(0)).which());
|
||||
REQUIRE(3 == variant_type(std::int64_t(0)).which());
|
||||
REQUIRE(4 == variant_type(double(0.0)).which());
|
||||
REQUIRE(5 == variant_type(float(0.0)).which());
|
||||
}
|
||||
|
||||
TEST_CASE("get with wrong type (here: double) should throw", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
variant_type var = 5;
|
||||
REQUIRE(var.is<int>());
|
||||
REQUIRE_FALSE(var.is<double>());
|
||||
REQUIRE(var.get<int>() == 5);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<double>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("get with wrong type (here: int) should throw", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
variant_type var = 5.0;
|
||||
REQUIRE(var.is<double>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
REQUIRE(var.get<double>() == 5.0);
|
||||
REQUIRE(mapbox::util::get<double>(var) == 5.0);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<int>(var);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("get on const varint with wrong type (here: int) should throw", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
const variant_type var = 5.0;
|
||||
REQUIRE(var.is<double>());
|
||||
REQUIRE_FALSE(var.is<int>());
|
||||
REQUIRE(var.get<double>() == 5.0);
|
||||
REQUIRE(mapbox::util::get<double>(var) == 5.0);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<int>(var);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("get with any type should throw if not initialized", "[variant]")
|
||||
{
|
||||
mapbox::util::variant<int, double> var{mapbox::util::no_init()};
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<double>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("no_init variant can be copied and moved from", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
|
||||
variant_type v1{mapbox::util::no_init()};
|
||||
variant_type v2{42};
|
||||
variant_type v3{23};
|
||||
|
||||
REQUIRE(v2.get<int>() == 42);
|
||||
v2 = v1;
|
||||
REQUIRE_THROWS_AS({
|
||||
v2.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
|
||||
REQUIRE(v3.get<int>() == 23);
|
||||
v3 = std::move(v1);
|
||||
REQUIRE_THROWS_AS({
|
||||
v3.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("no_init variant can be copied and moved to", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
|
||||
variant_type v1{42};
|
||||
variant_type v2{mapbox::util::no_init()};
|
||||
variant_type v3{mapbox::util::no_init()};
|
||||
|
||||
REQUIRE_THROWS_AS({
|
||||
v2.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
|
||||
REQUIRE(v1.get<int>() == 42);
|
||||
v2 = v1;
|
||||
REQUIRE(v2.get<int>() == 42);
|
||||
REQUIRE(v1.get<int>() == 42);
|
||||
|
||||
REQUIRE_THROWS_AS({
|
||||
v3.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
|
||||
v3 = std::move(v1);
|
||||
REQUIRE(v3.get<int>() == 42);
|
||||
}
|
||||
|
||||
TEST_CASE("implicit conversion", "[variant][implicit conversion]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int>;
|
||||
variant_type var(5.0); // converted to int
|
||||
REQUIRE(var.get<int>() == 5);
|
||||
var = 6.0; // works for operator=, too
|
||||
REQUIRE(var.get<int>() == 6);
|
||||
}
|
||||
|
||||
TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<long, char>;
|
||||
variant_type var = 5.0; // converted to long
|
||||
REQUIRE(var.get<long>() == 5);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<char>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("implicit conversion to unsigned char", "[variant][implicit conversion]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<unsigned char>;
|
||||
variant_type var = 100.0;
|
||||
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
|
||||
CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
|
||||
}
|
||||
|
||||
struct dummy
|
||||
{
|
||||
};
|
||||
|
||||
TEST_CASE("implicit conversion to a suitable type", "[variant][implicit conversion]")
|
||||
{
|
||||
using mapbox::util::variant;
|
||||
CHECK_NOTHROW((variant<dummy, float, std::string>(123)).get<float>());
|
||||
CHECK_NOTHROW((variant<dummy, float, std::string>("foo")).get<std::string>());
|
||||
}
|
||||
|
||||
TEST_CASE("value_traits for non-convertible type", "[variant::detail]")
|
||||
{
|
||||
namespace detail = mapbox::util::detail;
|
||||
using target_type = detail::value_traits<dummy, int>::target_type;
|
||||
CHECK((std::is_same<target_type, void>::value) == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Type indexing should work with variants with duplicated types", "[variant::detail]")
|
||||
{
|
||||
// Index is in reverse order
|
||||
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
|
||||
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, double, int>::index == 3));
|
||||
REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
|
||||
REQUIRE((mapbox::util::detail::value_traits<int, bool, int, double, int>::index == 2));
|
||||
REQUIRE((mapbox::util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
|
||||
REQUIRE((mapbox::util::detail::value_traits<bool, bool, int, bool, std::string>::index == 3));
|
||||
REQUIRE((mapbox::util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
|
||||
REQUIRE((mapbox::util::detail::value_traits<dummy, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
|
||||
REQUIRE((mapbox::util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == mapbox::util::detail::invalid_value));
|
||||
}
|
||||
|
||||
TEST_CASE("variant default constructor", "[variant][default constructor]")
|
||||
{
|
||||
// By default variant is initialised with (default constructed) first type in template parameters pack
|
||||
// As a result first type in Types... must be default constructable
|
||||
// NOTE: index in reverse order -> index = N - 1
|
||||
using variant_type = mapbox::util::variant<int, double, std::string>;
|
||||
REQUIRE(variant_type{}.which() == 0);
|
||||
REQUIRE(variant_type{}.valid());
|
||||
REQUIRE_FALSE(variant_type{mapbox::util::no_init()}.valid());
|
||||
}
|
||||
|
||||
TEST_CASE("variant printer", "[visitor][unary visitor][printer]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double, std::string>;
|
||||
std::vector<variant_type> var = {2.1, 123, "foo", 456};
|
||||
std::stringstream out;
|
||||
std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
|
||||
out << var[2];
|
||||
REQUIRE(out.str() == "2.1,123,foo,456,foo");
|
||||
}
|
||||
|
||||
TEST_CASE("swapping variants should do the right thing", "[variant]")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, double, std::string>;
|
||||
variant_type a = 7;
|
||||
variant_type b = 3;
|
||||
variant_type c = 3.141;
|
||||
variant_type d = "foo";
|
||||
variant_type e = "a long string that is longer than small string optimization";
|
||||
|
||||
using std::swap;
|
||||
swap(a, b);
|
||||
REQUIRE(a.get<int>() == 3);
|
||||
REQUIRE(a.which() == 0);
|
||||
REQUIRE(b.get<int>() == 7);
|
||||
REQUIRE(b.which() == 0);
|
||||
|
||||
swap(b, c);
|
||||
REQUIRE(b.get<double>() == Approx(3.141));
|
||||
REQUIRE(b.which() == 1);
|
||||
REQUIRE(c.get<int>() == 7);
|
||||
REQUIRE(c.which() == 0);
|
||||
|
||||
swap(b, d);
|
||||
REQUIRE(b.get<std::string>() == "foo");
|
||||
REQUIRE(b.which() == 2);
|
||||
REQUIRE(d.get<double>() == Approx(3.141));
|
||||
REQUIRE(d.which() == 1);
|
||||
|
||||
swap(b, e);
|
||||
REQUIRE(b.get<std::string>() == "a long string that is longer than small string optimization");
|
||||
REQUIRE(b.which() == 2);
|
||||
REQUIRE(e.get<std::string>() == "foo");
|
||||
REQUIRE(e.which() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("variant should work with equality operators")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, std::string>;
|
||||
|
||||
variant_type a{1};
|
||||
variant_type b{1};
|
||||
variant_type c{2};
|
||||
variant_type s{"foo"};
|
||||
|
||||
REQUIRE(a == a);
|
||||
REQUIRE(a == b);
|
||||
REQUIRE_FALSE(a == c);
|
||||
REQUIRE_FALSE(a == s);
|
||||
REQUIRE_FALSE(c == s);
|
||||
|
||||
REQUIRE_FALSE(a != a);
|
||||
REQUIRE_FALSE(a != b);
|
||||
REQUIRE(a != c);
|
||||
REQUIRE(a != s);
|
||||
REQUIRE(c != s);
|
||||
}
|
||||
|
||||
TEST_CASE("variant should work with comparison operators")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<int, std::string>;
|
||||
|
||||
variant_type a{1};
|
||||
variant_type b{1};
|
||||
variant_type c{2};
|
||||
variant_type s{"foo"};
|
||||
variant_type t{"bar"};
|
||||
|
||||
REQUIRE_FALSE(a < a);
|
||||
REQUIRE_FALSE(a < b);
|
||||
REQUIRE(a < c);
|
||||
REQUIRE(a < s);
|
||||
REQUIRE(c < s);
|
||||
REQUIRE(t < s);
|
||||
|
||||
REQUIRE_FALSE(a > a);
|
||||
REQUIRE_FALSE(a > b);
|
||||
REQUIRE_FALSE(a > c);
|
||||
REQUIRE_FALSE(a > s);
|
||||
REQUIRE_FALSE(c > s);
|
||||
REQUIRE_FALSE(t > s);
|
||||
|
||||
REQUIRE(a <= a);
|
||||
REQUIRE(a <= b);
|
||||
REQUIRE(a <= c);
|
||||
REQUIRE(a <= s);
|
||||
REQUIRE(c <= s);
|
||||
REQUIRE(t <= s);
|
||||
|
||||
REQUIRE(a >= a);
|
||||
REQUIRE(a >= b);
|
||||
REQUIRE_FALSE(a >= c);
|
||||
REQUIRE_FALSE(a >= s);
|
||||
REQUIRE_FALSE(c >= s);
|
||||
REQUIRE_FALSE(t >= s);
|
||||
}
|
||||
|
||||
TEST_CASE("storing reference wrappers works")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<std::reference_wrapper<int>, std::reference_wrapper<double>>;
|
||||
|
||||
int a = 1;
|
||||
variant_type v{std::ref(a)};
|
||||
REQUIRE(v.get<int>() == 1);
|
||||
REQUIRE(mapbox::util::get<int>(v) == 1);
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<double>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<double>(v);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
a = 2;
|
||||
REQUIRE(v.get<int>() == 2);
|
||||
v.get<int>() = 3;
|
||||
REQUIRE(a == 3);
|
||||
|
||||
double b = 3.141;
|
||||
v = std::ref(b);
|
||||
REQUIRE(v.get<double>() == Approx(3.141));
|
||||
REQUIRE(mapbox::util::get<double>(v) == Approx(3.141));
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<int>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<int>(v);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
b = 2.718;
|
||||
REQUIRE(v.get<double>() == Approx(2.718));
|
||||
a = 3;
|
||||
REQUIRE(v.get<double>() == Approx(2.718));
|
||||
v.get<double>() = 4.1;
|
||||
REQUIRE(b == Approx(4.1));
|
||||
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<int>() = 4;
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("storing reference wrappers to consts works")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<std::reference_wrapper<int const>, std::reference_wrapper<double const>>;
|
||||
|
||||
int a = 1;
|
||||
variant_type v{std::cref(a)};
|
||||
REQUIRE(v.get<int const>() == 1);
|
||||
REQUIRE(v.get<int>() == 1); // this works (see #82)
|
||||
REQUIRE(mapbox::util::get<int const>(v) == 1);
|
||||
// REQUIRE(mapbox::util::get<int>(v) == 1); // this doesn't work (see #82)
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<double const>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<double const>(v);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
|
||||
double b = 3.141;
|
||||
v = std::cref(b);
|
||||
REQUIRE(v.get<double const>() == Approx(3.141));
|
||||
REQUIRE(mapbox::util::get<double const>(v) == Approx(3.141));
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<int const>();
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
REQUIRE_THROWS_AS({
|
||||
mapbox::util::get<int const>(v);
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
126
test/unique_ptr_test.cpp
Normal file
126
test/unique_ptr_test.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
namespace test {
|
||||
|
||||
struct add;
|
||||
struct sub;
|
||||
|
||||
template <typename OpTag>
|
||||
struct binary_op;
|
||||
|
||||
typedef util::variant<int,
|
||||
std::unique_ptr<binary_op<add>>,
|
||||
std::unique_ptr<binary_op<sub>>>
|
||||
expression;
|
||||
|
||||
template <typename Op>
|
||||
struct binary_op
|
||||
{
|
||||
expression left; // variant instantiated here...
|
||||
expression right;
|
||||
|
||||
binary_op(expression&& lhs, expression&& rhs)
|
||||
: left(std::move(lhs)), right(std::move(rhs))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct print
|
||||
{
|
||||
template <typename T>
|
||||
void operator()(T const& val) const
|
||||
{
|
||||
std::cerr << val << ":" << typeid(T).name() << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct test
|
||||
{
|
||||
template <typename T>
|
||||
std::string operator()(T const& obj) const
|
||||
{
|
||||
return std::string("TYPE_ID=") + typeid(obj).name();
|
||||
}
|
||||
};
|
||||
|
||||
struct calculator
|
||||
{
|
||||
public:
|
||||
int operator()(int value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
int operator()(std::unique_ptr<binary_op<add>> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(calculator(), binary->left) + util::apply_visitor(calculator(), binary->right);
|
||||
}
|
||||
|
||||
int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(calculator(), binary->left) - util::apply_visitor(calculator(), binary->right);
|
||||
}
|
||||
};
|
||||
|
||||
struct to_string
|
||||
{
|
||||
public:
|
||||
std::string operator()(int value) const
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
|
||||
std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(to_string(), binary->left) + std::string("+") + util::apply_visitor(to_string(), binary->right);
|
||||
}
|
||||
|
||||
std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
|
||||
{
|
||||
return util::apply_visitor(to_string(), binary->left) + std::string("-") + util::apply_visitor(to_string(), binary->right);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
|
||||
|
||||
test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
|
||||
test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
|
||||
|
||||
std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
|
||||
|
||||
int total = 0;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
for (std::size_t i = 0; i < NUM_ITER; ++i)
|
||||
{
|
||||
total += util::apply_visitor(test::calculator(), result);
|
||||
}
|
||||
}
|
||||
std::cerr << "total=" << total << std::endl;
|
||||
|
||||
std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
2
test/unit.cpp
Normal file
2
test/unit.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
35
variant.gyp
Normal file
35
variant.gyp
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"includes": [
|
||||
"common.gypi"
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "tests",
|
||||
"type": "executable",
|
||||
"sources": [
|
||||
"test/unit.cpp",
|
||||
"test/t/binary_visitor_1.cpp",
|
||||
"test/t/binary_visitor_2.cpp",
|
||||
"test/t/binary_visitor_3.cpp",
|
||||
"test/t/binary_visitor_4.cpp",
|
||||
"test/t/binary_visitor_5.cpp",
|
||||
"test/t/binary_visitor_6.cpp",
|
||||
"test/t/issue21.cpp",
|
||||
"test/t/mutating_visitor.cpp",
|
||||
"test/t/optional.cpp",
|
||||
"test/t/recursive_wrapper.cpp",
|
||||
"test/t/sizeof.cpp",
|
||||
"test/t/unary_visitor.cpp",
|
||||
"test/t/variant.cpp"
|
||||
],
|
||||
"xcode_settings": {
|
||||
"SDKROOT": "macosx",
|
||||
"SUPPORTED_PLATFORMS":["macosx"]
|
||||
},
|
||||
"include_dirs": [
|
||||
"./",
|
||||
"test/include"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
901
variant.hpp
Normal file
901
variant.hpp
Normal file
@ -0,0 +1,901 @@
|
||||
#ifndef MAPBOX_UTIL_VARIANT_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef> // size_t
|
||||
#include <new> // operator new
|
||||
#include <stdexcept> // runtime_error
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include "recursive_wrapper.hpp"
|
||||
|
||||
// clang-format off
|
||||
// [[deprecated]] is only available in C++14, use this for the time being
|
||||
#if __cplusplus <= 201103L
|
||||
# ifdef __GNUC__
|
||||
# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
|
||||
# elif defined(_MSC_VER)
|
||||
# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
|
||||
# else
|
||||
# define MAPBOX_VARIANT_DEPRECATED
|
||||
# endif
|
||||
#else
|
||||
# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
|
||||
#ifdef NDEBUG
|
||||
#define VARIANT_INLINE __forceinline
|
||||
#else
|
||||
#define VARIANT_INLINE __declspec(noinline)
|
||||
#endif
|
||||
#else
|
||||
#ifdef NDEBUG
|
||||
#define VARIANT_INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
#define VARIANT_INLINE __attribute__((noinline))
|
||||
#endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#define VARIANT_MAJOR_VERSION 1
|
||||
#define VARIANT_MINOR_VERSION 1
|
||||
#define VARIANT_PATCH_VERSION 0
|
||||
|
||||
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
|
||||
// XXX This should derive from std::logic_error instead of std::runtime_error.
|
||||
// See https://github.com/mapbox/variant/issues/48 for details.
|
||||
class bad_variant_access : public std::runtime_error
|
||||
{
|
||||
|
||||
public:
|
||||
explicit bad_variant_access(const std::string& what_arg)
|
||||
: runtime_error(what_arg) {}
|
||||
|
||||
explicit bad_variant_access(const char* what_arg)
|
||||
: runtime_error(what_arg) {}
|
||||
|
||||
}; // class bad_variant_access
|
||||
|
||||
template <typename R = void>
|
||||
struct MAPBOX_VARIANT_DEPRECATED static_visitor
|
||||
{
|
||||
using result_type = R;
|
||||
|
||||
protected:
|
||||
static_visitor() {}
|
||||
~static_visitor() {}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
static constexpr std::size_t invalid_value = std::size_t(-1);
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct direct_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct direct_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t index = std::is_same<T, First>::value
|
||||
? sizeof...(Types)
|
||||
: direct_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct direct_type<T>
|
||||
{
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct convertible_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct convertible_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t index = std::is_convertible<T, First>::value
|
||||
? sizeof...(Types)
|
||||
: convertible_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct convertible_type<T>
|
||||
{
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct value_traits
|
||||
{
|
||||
using value_type = typename std::remove_reference<T>::type;
|
||||
static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
|
||||
static constexpr bool is_direct = direct_index != invalid_value;
|
||||
static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
|
||||
static constexpr bool is_valid = index != invalid_value;
|
||||
static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
|
||||
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
|
||||
};
|
||||
|
||||
// check if T is in Types...
|
||||
template <typename T, typename... Types>
|
||||
struct has_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct has_type<T, First, Types...>
|
||||
{
|
||||
static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct has_type<T> : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct is_valid_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct is_valid_type<T, First, Types...>
|
||||
{
|
||||
static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_valid_type<T> : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename R = void>
|
||||
struct enable_if_type
|
||||
{
|
||||
using type = R;
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename Enable = void>
|
||||
struct result_of_unary_visit
|
||||
{
|
||||
using type = typename std::result_of<F(V&)>::type;
|
||||
};
|
||||
|
||||
template <typename F, typename V>
|
||||
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
|
||||
{
|
||||
using type = typename F::result_type;
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename Enable = void>
|
||||
struct result_of_binary_visit
|
||||
{
|
||||
using type = typename std::result_of<F(V&, V&)>::type;
|
||||
};
|
||||
|
||||
template <typename F, typename V>
|
||||
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
|
||||
{
|
||||
using type = typename F::result_type;
|
||||
};
|
||||
|
||||
template <std::size_t arg1, std::size_t... others>
|
||||
struct static_max;
|
||||
|
||||
template <std::size_t arg>
|
||||
struct static_max<arg>
|
||||
{
|
||||
static const std::size_t value = arg;
|
||||
};
|
||||
|
||||
template <std::size_t arg1, std::size_t arg2, std::size_t... others>
|
||||
struct static_max<arg1, arg2, others...>
|
||||
{
|
||||
static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
struct variant_helper;
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct variant_helper<T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
|
||||
{
|
||||
if (type_index == sizeof...(Types))
|
||||
{
|
||||
reinterpret_cast<T*>(data)->~T();
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::destroy(type_index, data);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
|
||||
{
|
||||
if (old_type_index == sizeof...(Types))
|
||||
{
|
||||
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::move(old_type_index, old_value, new_value);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
|
||||
{
|
||||
if (old_type_index == sizeof...(Types))
|
||||
{
|
||||
new (new_value) T(*reinterpret_cast<const T*>(old_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::copy(old_type_index, old_value, new_value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_helper<>
|
||||
{
|
||||
VARIANT_INLINE static void destroy(const std::size_t, void*) {}
|
||||
VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
|
||||
VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper
|
||||
{
|
||||
static T const& apply_const(T const& obj) { return obj; }
|
||||
static T& apply(T& obj) { return obj; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper<recursive_wrapper<T>>
|
||||
{
|
||||
static auto apply_const(recursive_wrapper<T> const& obj)
|
||||
-> typename recursive_wrapper<T>::type const&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
static auto apply(recursive_wrapper<T>& obj)
|
||||
-> typename recursive_wrapper<T>::type&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper<std::reference_wrapper<T>>
|
||||
{
|
||||
static auto apply_const(std::reference_wrapper<T> const& obj)
|
||||
-> typename std::reference_wrapper<T>::type const&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
static auto apply(std::reference_wrapper<T>& obj)
|
||||
-> typename std::reference_wrapper<T>::type&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename... Types>
|
||||
struct dispatcher;
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v, F&& f)
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v.template get<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v, F&& f)
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T>
|
||||
struct dispatcher<F, V, R, T>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v.template get<T>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get<T>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher_rhs;
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
|
||||
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
if (rhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
if (rhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1>
|
||||
struct binary_dispatcher_rhs<F, V, R, T0, T1>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get<T1>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get<T1>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher_lhs;
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
|
||||
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
if (lhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
if (lhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1>
|
||||
struct binary_dispatcher_lhs<F, V, R, T0, T1>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get<T0>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get<T0>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename... Types>
|
||||
struct binary_dispatcher;
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
|
||||
{
|
||||
if (v0.template is<T>())
|
||||
{
|
||||
if (v1.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v0.template get<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
else if (v1.template is<T>())
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
|
||||
{
|
||||
if (v0.template is<T>())
|
||||
{
|
||||
if (v1.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v0.template get<T>()),
|
||||
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
else if (v1.template is<T>())
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T>
|
||||
struct binary_dispatcher<F, V, R, T>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v0.template get<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply(v0.template get<T>()),
|
||||
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
|
||||
}
|
||||
};
|
||||
|
||||
// comparator functors
|
||||
struct equal_comp
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(T const& lhs, T const& rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct less_comp
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(T const& lhs, T const& rhs) const
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Variant, typename Comp>
|
||||
class comparer
|
||||
{
|
||||
public:
|
||||
explicit comparer(Variant const& lhs) noexcept
|
||||
: lhs_(lhs) {}
|
||||
comparer& operator=(comparer const&) = delete;
|
||||
// visitor
|
||||
template <typename T>
|
||||
bool operator()(T const& rhs_content) const
|
||||
{
|
||||
T const& lhs_content = lhs_.template get<T>();
|
||||
return Comp()(lhs_content, rhs_content);
|
||||
}
|
||||
|
||||
private:
|
||||
Variant const& lhs_;
|
||||
};
|
||||
|
||||
// True if Predicate matches for all of the types Ts
|
||||
template <template <typename> class Predicate, typename... Ts>
|
||||
struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
|
||||
std::tuple<typename Predicate<Ts>::type..., std::true_type>>
|
||||
{
|
||||
};
|
||||
|
||||
// True if Predicate matches for none of the types Ts
|
||||
template <template <typename> class Predicate, typename... Ts>
|
||||
struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
|
||||
std::tuple<typename Predicate<Ts>::type..., std::false_type>>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct no_init
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
class variant
|
||||
{
|
||||
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
|
||||
static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
|
||||
|
||||
private:
|
||||
static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
|
||||
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
|
||||
|
||||
using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
|
||||
using data_type = typename std::aligned_storage<data_size, data_align>::type;
|
||||
using helper_type = detail::variant_helper<Types...>;
|
||||
|
||||
std::size_t type_index;
|
||||
data_type data;
|
||||
|
||||
public:
|
||||
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
|
||||
: type_index(sizeof...(Types)-1)
|
||||
{
|
||||
static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
|
||||
new (&data) first_type();
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(no_init) noexcept
|
||||
: type_index(detail::invalid_value) {}
|
||||
|
||||
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
|
||||
template <typename T, typename Traits = detail::value_traits<T, Types...>,
|
||||
typename Enable = typename std::enable_if<Traits::is_valid>::type>
|
||||
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
|
||||
: type_index(Traits::index)
|
||||
{
|
||||
new (&data) typename Traits::target_type(std::forward<T>(val));
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...> const& old)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::copy(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::move(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
private:
|
||||
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
helper_type::copy(rhs.type_index, &rhs.data, &data);
|
||||
type_index = rhs.type_index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
helper_type::move(rhs.type_index, &rhs.data, &data);
|
||||
type_index = rhs.type_index;
|
||||
}
|
||||
|
||||
public:
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
|
||||
{
|
||||
move_assign(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
|
||||
{
|
||||
copy_assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// conversions
|
||||
// move-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
|
||||
{
|
||||
variant<Types...> temp(std::forward<T>(rhs));
|
||||
move_assign(std::move(temp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// copy-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
|
||||
{
|
||||
variant<Types...> temp(rhs);
|
||||
copy_assign(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
VARIANT_INLINE bool is() const
|
||||
{
|
||||
static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
|
||||
return type_index == detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool valid() const
|
||||
{
|
||||
return type_index != detail::invalid_value;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
VARIANT_INLINE void set(Args&&... args)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
new (&data) T(std::forward<Args>(args)...);
|
||||
type_index = detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
// get<T>()
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T const*>(&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
// get<T>() - T stored as recursive_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
// get<T>() - T stored as std::reference_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
|
||||
// This function is deprecated because it returns an internal index field.
|
||||
// Use which() instead.
|
||||
MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
|
||||
{
|
||||
return type_index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE int which() const noexcept
|
||||
{
|
||||
return static_cast<int>(sizeof...(Types)-type_index - 1);
|
||||
}
|
||||
|
||||
// visitor
|
||||
// unary
|
||||
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static visit(V const& v, F&& f)
|
||||
-> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
|
||||
{
|
||||
return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static visit(V& v, F&& f)
|
||||
-> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
|
||||
{
|
||||
return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// binary
|
||||
// const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
~variant() noexcept // no-throw destructor
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
}
|
||||
|
||||
// comparison operators
|
||||
// equality
|
||||
VARIANT_INLINE bool operator==(variant const& rhs) const
|
||||
{
|
||||
assert(valid() && rhs.valid());
|
||||
if (this->which() != rhs.which())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
detail::comparer<variant, detail::equal_comp> visitor(*this);
|
||||
return visit(rhs, visitor);
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool operator!=(variant const& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
// less than
|
||||
VARIANT_INLINE bool operator<(variant const& rhs) const
|
||||
{
|
||||
assert(valid() && rhs.valid());
|
||||
if (this->which() != rhs.which())
|
||||
{
|
||||
return this->which() < rhs.which();
|
||||
}
|
||||
detail::comparer<variant, detail::less_comp> visitor(*this);
|
||||
return visit(rhs, visitor);
|
||||
}
|
||||
VARIANT_INLINE bool operator>(variant const& rhs) const
|
||||
{
|
||||
return rhs < *this;
|
||||
}
|
||||
VARIANT_INLINE bool operator<=(variant const& rhs) const
|
||||
{
|
||||
return !(*this > rhs);
|
||||
}
|
||||
VARIANT_INLINE bool operator>=(variant const& rhs) const
|
||||
{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
};
|
||||
|
||||
// unary visitor interface
|
||||
// const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
|
||||
{
|
||||
return V::visit(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
|
||||
{
|
||||
return V::visit(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// binary visitor interface
|
||||
// const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return V::binary_visit(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return V::binary_visit(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// getter interface
|
||||
template <typename ResultType, typename T>
|
||||
ResultType& get(T& var)
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
|
||||
template <typename ResultType, typename T>
|
||||
ResultType const& get(T const& var)
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_HPP
|
45
variant_io.hpp
Normal file
45
variant_io.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_IO_HPP
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
|
||||
namespace detail {
|
||||
// operator<< helper
|
||||
template <typename Out>
|
||||
class printer
|
||||
{
|
||||
public:
|
||||
explicit printer(Out& out)
|
||||
: out_(out) {}
|
||||
printer& operator=(printer const&) = delete;
|
||||
|
||||
// visitor
|
||||
template <typename T>
|
||||
void operator()(T const& operand) const
|
||||
{
|
||||
out_ << operand;
|
||||
}
|
||||
|
||||
private:
|
||||
Out& out_;
|
||||
};
|
||||
}
|
||||
|
||||
// operator<<
|
||||
template <typename CharT, typename Traits, typename... Types>
|
||||
VARIANT_INLINE std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
|
||||
{
|
||||
detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
|
||||
apply_visitor(visitor, rhs);
|
||||
return out;
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_IO_HPP
|
Loading…
Reference in New Issue
Block a user