Upgrade to mapbox/variant 1.1.4
This commit is contained in:
parent
20c8ac0272
commit
29b3caf529
1
third_party/variant/.gitignore
vendored
1
third_party/variant/.gitignore
vendored
@ -6,3 +6,4 @@ deps
|
||||
*.gcda
|
||||
*.gcno
|
||||
.ycm_extra_conf.pyc
|
||||
mason_packages
|
||||
|
3
third_party/variant/.gitmodules
vendored
Normal file
3
third_party/variant/.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule ".mason"]
|
||||
path = .mason
|
||||
url = https://github.com/mapbox/mason.git
|
59
third_party/variant/.travis.yml
vendored
59
third_party/variant/.travis.yml
vendored
@ -1,4 +1,4 @@
|
||||
language: c
|
||||
language: generic
|
||||
|
||||
sudo: false
|
||||
|
||||
@ -6,49 +6,50 @@ sudo: false
|
||||
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' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'clang-3.5', 'llvm-3.5-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' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6' ]
|
||||
packages: [ 'clang-3.6' ]
|
||||
addons_clang37: &clang37
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ]
|
||||
packages: [ 'clang-3.7', 'libboost1.55-all-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7' ]
|
||||
packages: [ 'clang-3.7' ]
|
||||
addons_clang38: &clang38
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ]
|
||||
packages: [ 'clang-3.8', 'libboost1.55-all-dev']
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8' ]
|
||||
packages: [ 'clang-3.8']
|
||||
addons_clang39: &clang39
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise' ]
|
||||
packages: [ 'clang-3.9']
|
||||
addons_gcc47: &gcc47
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.7', 'libboost1.55-all-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'g++-4.7' ]
|
||||
addons_gcc48: &gcc48
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.8', 'libboost1.55-all-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'g++-4.8' ]
|
||||
addons_gcc49: &gcc49
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-4.9', 'libboost1.55-all-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'g++-4.9' ]
|
||||
addons_gcc5: &gcc5
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ]
|
||||
packages: [ 'g++-5', 'libboost1.55-all-dev' ]
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'g++-5' ]
|
||||
|
||||
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
|
||||
env: CXX=clang++-3.5 COVERAGE=True
|
||||
addons: *clang35
|
||||
- os: linux
|
||||
compiler: "clang36"
|
||||
@ -56,7 +57,7 @@ matrix:
|
||||
addons: *clang36
|
||||
- os: linux
|
||||
compiler: "clang37"
|
||||
env: CXX=clang++-3.7 COVERAGE=True
|
||||
env: CXX=clang++-3.7
|
||||
addons: *clang37
|
||||
- os: linux
|
||||
compiler: "clang38"
|
||||
@ -66,6 +67,11 @@ matrix:
|
||||
compiler: "clang38"
|
||||
env: CXX=clang++-3.8 CXX_STD=c++14
|
||||
addons: *clang38
|
||||
# not whitelisted yet: https://github.com/travis-ci/apt-package-whitelist/issues/2764
|
||||
#- os: linux
|
||||
# compiler: "clang39"
|
||||
# env: CXX=clang++-3.9
|
||||
# addons: *clang39
|
||||
- os: linux
|
||||
compiler: "gcc47"
|
||||
env: CXX=g++-4.7
|
||||
@ -96,7 +102,6 @@ before_install:
|
||||
- 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
|
||||
@ -106,11 +111,7 @@ before_install:
|
||||
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
|
||||
- make sizes
|
||||
- scripts/run_compilation_failure_tests.sh
|
||||
- if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
|
||||
make clean;
|
||||
@ -123,5 +124,5 @@ script:
|
||||
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';
|
||||
./.local/bin/cpp-coveralls --gcov /usr/bin/llvm-cov-3.5 --gcov-options '\-lp' -i optional.hpp -i recursive_wrapper.hpp -i variant.hpp -i variant_io.hpp;
|
||||
fi
|
||||
|
19
third_party/variant/Jamroot
vendored
19
third_party/variant/Jamroot
vendored
@ -1,4 +1,4 @@
|
||||
# Inofficial and incomplete build file using Boost build system.
|
||||
# Unofficial and incomplete build file using Boost build system.
|
||||
# You should use make unless you know what you are doing.
|
||||
|
||||
local BOOST_DIR = "/usr/local" ;
|
||||
@ -17,9 +17,10 @@ exe variant-test
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<include>./include
|
||||
<include>./test/include
|
||||
#<define>SINGLE_THREADED
|
||||
<variant>release:<cxxflags>-march=native
|
||||
<variant>release:<cxxflags>"-march=native -Wweak-vtables"
|
||||
;
|
||||
|
||||
|
||||
@ -31,7 +32,8 @@ exe binary-visitor-test
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<include>./include
|
||||
<include>./test/include
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
@ -43,7 +45,8 @@ exe recursive-wrapper-test
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<include>./include
|
||||
<include>./test/include
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
@ -55,7 +58,8 @@ exe unique-ptr-test
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<include>./include
|
||||
<include>./test/include
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
||||
@ -68,6 +72,7 @@ exe reference_wrapper_test
|
||||
.//chrono
|
||||
:
|
||||
<include>$(BOOST_DIR)/include
|
||||
<include>./
|
||||
<include>./include
|
||||
<include>./test/include
|
||||
<variant>release:<cxxflags>-march=native
|
||||
;
|
||||
|
77
third_party/variant/Makefile
vendored
77
third_party/variant/Makefile
vendored
@ -1,32 +1,23 @@
|
||||
MASON = .mason/mason
|
||||
BOOST_VERSION = boost 1.60.0
|
||||
|
||||
CXX := $(CXX)
|
||||
CXX_STD ?= c++11
|
||||
|
||||
BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
|
||||
BOOST_FLAGS = `$(MASON) cflags $(BOOST_VERSION)`
|
||||
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
|
||||
ALL_HEADERS = $(shell find include/mapbox/ '(' -name '*.hpp' ')')
|
||||
|
||||
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 out/lambda_overload_test out/hashable_test
|
||||
|
||||
all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
|
||||
mason_packages:
|
||||
git submodule update --init .mason
|
||||
$(MASON) install $(BOOST_VERSION)
|
||||
|
||||
./deps/gyp:
|
||||
git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
|
||||
@ -36,25 +27,33 @@ gyp: ./deps/gyp
|
||||
make V=1 -C ./out tests
|
||||
./out/Release/tests
|
||||
|
||||
out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
|
||||
out/bench-variant-debug: Makefile mason_packages test/bench_variant.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./include -Itest/include -pthreads $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/bench-variant: Makefile test/bench_variant.cpp variant.hpp recursive_wrapper.hpp
|
||||
out/bench-variant: Makefile mason_packages test/bench_variant.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp recursive_wrapper.hpp
|
||||
out/unique_ptr_test: Makefile mason_packages test/unique_ptr_test.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp recursive_wrapper.hpp
|
||||
out/recursive_wrapper_test: Makefile mason_packages test/recursive_wrapper_test.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp variant_io.hpp recursive_wrapper.hpp
|
||||
out/binary_visitor_test: Makefile mason_packages test/binary_visitor_test.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
|
||||
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/lambda_overload_test: Makefile mason_packages test/lambda_overload_test.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/lambda_overload_test test/lambda_overload_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
out/hashable_test: Makefile mason_packages test/hashable_test.cpp
|
||||
mkdir -p ./out
|
||||
$(CXX) -o out/hashable_test test/hashable_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)
|
||||
|
||||
bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
|
||||
./out/bench-variant 100000
|
||||
@ -66,11 +65,11 @@ 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
|
||||
out/%.o: test/t/%.cpp Makefile $(ALL_HEADERS)
|
||||
mkdir -p ./out
|
||||
$(CXX) -c -o $@ $< -I. -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS)
|
||||
$(CXX) -c -o $@ $< -Iinclude -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
|
||||
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/issue122.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)
|
||||
|
||||
@ -79,14 +78,14 @@ test: 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)
|
||||
$(CXX) -o out/cov-test --coverage test/unit.cpp test/t/*.cpp -I./include -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
|
||||
|
||||
sizes: Makefile variant.hpp recursive_wrapper.hpp
|
||||
sizes: Makefile
|
||||
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
|
||||
@$(CXX) -o ./out/our_variant_hello_world.out include/mapbox/variant.hpp -I./include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world.out
|
||||
@$(CXX) -o ./out/boost_variant_hello_world.out `$(MASON) prefix boost 1.60.0`/include/boost/variant.hpp -I./include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(BOOST_FLAGS) && du -h ./out/boost_variant_hello_world.out
|
||||
@$(CXX) -o ./out/our_variant_hello_world ./test/our_variant_hello_world.cpp -I./include $(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./include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(BOOST_FLAGS) && du -h ./out/boost_variant_hello_world
|
||||
|
||||
profile: out/bench-variant-debug
|
||||
mkdir -p profiling/
|
||||
@ -102,9 +101,9 @@ clean:
|
||||
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
|
||||
pgo: out Makefile
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS) -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
|
||||
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS) -fprofile-use
|
||||
|
||||
.PHONY: sizes test
|
||||
|
181
third_party/variant/README.md
vendored
181
third_party/variant/README.md
vendored
@ -1,11 +1,169 @@
|
||||
# Mapbox Variant
|
||||
|
||||
An alternative to `boost::variant` for C++11.
|
||||
An header-only alternative to `boost::variant` for C++11 and C++14
|
||||
|
||||
[](https://travis-ci.org/mapbox/variant)
|
||||
[](https://ci.appveyor.com/project/Mapbox/variant)
|
||||
[](https://coveralls.io/r/mapbox/variant?branch=master)
|
||||
|
||||
## Introduction
|
||||
|
||||
Variant's basic building blocks are:
|
||||
- `variant<Ts...>` - a type-safe representation for sum-types / discriminated unions
|
||||
- `recursive_wrapper<T>` - a helper type to represent recursive "tree-like" variants
|
||||
- `apply_visitor(visitor, myVariant)` - to invoke a custom visitor on the variant's underlying type
|
||||
- `get<T>()` - a function to directly unwrap a variant's underlying type
|
||||
- `.match([](Type){})` - a variant convenience member function taking an arbitrary number of lambdas creating a visitor behind the scenes and applying it to the variant
|
||||
|
||||
|
||||
### Basic Usage - HTTP API Example
|
||||
|
||||
Suppose you want to represent a HTTP API response which is either a JSON result or an error:
|
||||
|
||||
```c++
|
||||
struct Result {
|
||||
Json object;
|
||||
};
|
||||
|
||||
struct Error {
|
||||
int32_t code;
|
||||
string message;
|
||||
};
|
||||
```
|
||||
|
||||
You can represent this at type level using a variant which is either an `Error` or a `Result`:
|
||||
|
||||
```c++
|
||||
using Response = variant<Error, Result>;
|
||||
|
||||
Response makeRequest() {
|
||||
return Error{501, "Not Implemented"};
|
||||
}
|
||||
|
||||
Response ret = makeRequest();
|
||||
```
|
||||
|
||||
To see which type the `Response` holds you pattern match on the variant unwrapping the underlying value:
|
||||
|
||||
```c++
|
||||
ret.match([] (Result r) { print(r.object); }
|
||||
[] (Error e) { print(e.message); });
|
||||
```
|
||||
|
||||
Instead of using the variant's convenience `.match` pattern matching function you can create a type visitor functor and use `apply_visitor` manually:
|
||||
|
||||
```c++
|
||||
struct ResponseVisitor {
|
||||
void operator()(Result r) const {
|
||||
print(r.object);
|
||||
}
|
||||
|
||||
void operator()(Error e) const {
|
||||
print(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
ResponseVisitor visitor;
|
||||
apply_visitor(visitor, ret);
|
||||
```
|
||||
|
||||
In both cases the compiler makes sure you handle all types the variant can represent at compile.
|
||||
|
||||
|
||||
### Recursive Variants - JSON Example
|
||||
|
||||
[JSON](http://www.json.org/) consists of types `String`, `Number`, `True`, `False`, `Null`, `Array` and `Object`.
|
||||
|
||||
|
||||
```c++
|
||||
struct String { string value; };
|
||||
struct Number { double value; };
|
||||
struct True { };
|
||||
struct False { };
|
||||
struct Null { };
|
||||
struct Array { vector<?> values; };
|
||||
struct Object { unordered_map<string, ?> values; };
|
||||
```
|
||||
|
||||
This works for primitive types but how do we represent recursive types such as `Array` which can hold multiple elements and `Array` itself, too?
|
||||
|
||||
For these use cases Variant provides a `recursive_wrapper` helper type which lets you express recursive Variants.
|
||||
|
||||
```c++
|
||||
struct String { string value; };
|
||||
struct Number { double value; };
|
||||
struct True { };
|
||||
struct False { };
|
||||
struct Null { };
|
||||
|
||||
// Forward declarations only
|
||||
struct Array;
|
||||
struct Object;
|
||||
|
||||
using Value = variant<String, Number, True, False, Null, recursive_wrapper<Array>, recursive_wrapper<Object>>;
|
||||
|
||||
struct Array {
|
||||
vector<Value> values;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
unordered_map<string, Value> values;
|
||||
};
|
||||
```
|
||||
|
||||
For walkig the JSON representation you can again either create a `JSONVisitor`:
|
||||
|
||||
```c++
|
||||
struct JSONVisitor {
|
||||
|
||||
void operator()(Null) const {
|
||||
print("null");
|
||||
}
|
||||
|
||||
// same for all other JSON types
|
||||
};
|
||||
|
||||
JSONVisitor visitor;
|
||||
apply_visitor(visitor, json);
|
||||
```
|
||||
|
||||
Or use the convenience `.match` pattern matching function:
|
||||
|
||||
```c++
|
||||
json.match([] (Null) { print("null"); },
|
||||
...);
|
||||
```
|
||||
|
||||
To summarize: use `recursive_wrapper` to represent recursive "tree-like" representations:
|
||||
|
||||
```c++
|
||||
struct Empty { };
|
||||
struct Node;
|
||||
|
||||
using Tree = variant<Empty, recursive_wrapper<Node>>;
|
||||
|
||||
struct Node {
|
||||
uint64_t value;
|
||||
}
|
||||
```
|
||||
### Advanced Usage Tips
|
||||
|
||||
Creating type aliases for variants is a great way to reduce repetition.
|
||||
Keep in mind those type aliases are not checked at type level, though.
|
||||
We recommend creating a new type for all but basic variant usage:
|
||||
|
||||
```c++
|
||||
// the compiler can't tell the following two apart
|
||||
using APIResult = variant<Error, Result>;
|
||||
using FilesystemResult = variant<Error, Result>;
|
||||
|
||||
// new type
|
||||
struct APIResult : variant<Error, Result> {
|
||||
using Base = variant<Error, Result>;
|
||||
using Base::Base;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Why use Mapbox Variant?
|
||||
|
||||
@ -45,6 +203,9 @@ implementations](doc/other_implementations.md).
|
||||
Want to know more about the upcoming standard? Have a look at our
|
||||
[overview](doc/standards_effort.md).
|
||||
|
||||
Most modern high-level languages provide ways to express sum types directly.
|
||||
If you're curious have a look at Haskell's pattern matching or Rust's and Swift's enums.
|
||||
|
||||
|
||||
## Depends
|
||||
|
||||
@ -55,19 +216,14 @@ Tested with:
|
||||
- g++-4.7
|
||||
- g++-4.8
|
||||
- g++-4.9
|
||||
- g++-5
|
||||
- g++-5.2
|
||||
- clang++-3.5
|
||||
- clang++-3.6
|
||||
- clang++-3.7
|
||||
- clang++-3.8
|
||||
- clang++-3.9
|
||||
- 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
|
||||
|
||||
@ -93,15 +249,6 @@ On Windows run `scripts/build-local.bat`.
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
@ -22,7 +22,7 @@ class optional
|
||||
|
||||
variant<none_type, T> variant_;
|
||||
|
||||
public:
|
||||
public:
|
||||
optional() = default;
|
||||
|
||||
optional(optional const& rhs)
|
@ -29,7 +29,7 @@ class recursive_wrapper
|
||||
this->get() = rhs;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
using type = T;
|
||||
|
||||
/**
|
||||
@ -42,9 +42,9 @@ class recursive_wrapper
|
||||
* @throws any exception thrown by the default constructur of T.
|
||||
*/
|
||||
recursive_wrapper()
|
||||
: p_(new T){};
|
||||
: p_(new T){}
|
||||
|
||||
~recursive_wrapper() noexcept { delete p_; };
|
||||
~recursive_wrapper() noexcept { delete p_; }
|
||||
|
||||
recursive_wrapper(recursive_wrapper const& operand)
|
||||
: p_(new T(operand.get())) {}
|
@ -10,8 +10,10 @@
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
#include "recursive_wrapper.hpp"
|
||||
#include <mapbox/recursive_wrapper.hpp>
|
||||
#include <mapbox/variant_visitor.hpp>
|
||||
|
||||
// clang-format off
|
||||
// [[deprecated]] is only available in C++14, use this for the time being
|
||||
@ -29,21 +31,26 @@
|
||||
|
||||
|
||||
#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
|
||||
// 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
|
||||
# ifdef NDEBUG
|
||||
# define VARIANT_INLINE //inline __attribute__((always_inline))
|
||||
# else
|
||||
# define VARIANT_INLINE __attribute__((noinline))
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// Exceptions
|
||||
#if defined( __EXCEPTIONS) || defined( _MSC_VER)
|
||||
#define HAS_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#define VARIANT_MAJOR_VERSION 1
|
||||
#define VARIANT_MINOR_VERSION 1
|
||||
#define VARIANT_PATCH_VERSION 0
|
||||
@ -58,7 +65,7 @@ namespace util {
|
||||
class bad_variant_access : public std::runtime_error
|
||||
{
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit bad_variant_access(const std::string& what_arg)
|
||||
: runtime_error(what_arg) {}
|
||||
|
||||
@ -72,7 +79,7 @@ struct MAPBOX_VARIANT_DEPRECATED static_visitor
|
||||
{
|
||||
using result_type = R;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
static_visitor() {}
|
||||
~static_visitor() {}
|
||||
};
|
||||
@ -88,8 +95,8 @@ 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;
|
||||
? sizeof...(Types)
|
||||
: direct_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -98,6 +105,26 @@ struct direct_type<T>
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
#if __cpp_lib_logical_traits >= 201510L
|
||||
|
||||
using std::disjunction;
|
||||
|
||||
#else
|
||||
|
||||
template <typename...>
|
||||
struct disjunction : std::false_type {};
|
||||
|
||||
template <typename B1>
|
||||
struct disjunction<B1> : B1 {};
|
||||
|
||||
template <typename B1, typename B2>
|
||||
struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
|
||||
|
||||
template <typename B1, typename... Bs>
|
||||
struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct convertible_type;
|
||||
|
||||
@ -105,8 +132,8 @@ 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;
|
||||
? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
|
||||
: convertible_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -118,7 +145,7 @@ struct convertible_type<T>
|
||||
template <typename T, typename... Types>
|
||||
struct value_traits
|
||||
{
|
||||
using value_type = typename std::remove_reference<T>::type;
|
||||
using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::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;
|
||||
@ -127,35 +154,6 @@ struct value_traits
|
||||
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
|
||||
{
|
||||
@ -299,7 +297,7 @@ struct dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v.template get<T>()));
|
||||
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -311,7 +309,7 @@ struct dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get<T>()));
|
||||
return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -325,12 +323,12 @@ 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>()));
|
||||
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get<T>()));
|
||||
return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -344,8 +342,8 @@ struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
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>()));
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -357,8 +355,8 @@ struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
if (rhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get<T1>()));
|
||||
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -372,14 +370,14 @@ 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>()));
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get_unchecked<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>()));
|
||||
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -393,8 +391,8 @@ struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
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>()));
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -406,8 +404,8 @@ struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
if (lhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get<T0>()));
|
||||
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -421,14 +419,14 @@ 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>()));
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get_unchecked<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>()));
|
||||
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -444,8 +442,8 @@ struct binary_dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
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
|
||||
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -465,8 +463,8 @@ struct binary_dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
if (v1.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v0.template get<T>()),
|
||||
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
|
||||
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -486,14 +484,14 @@ 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
|
||||
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get_unchecked<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
|
||||
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
};
|
||||
|
||||
@ -519,7 +517,7 @@ struct less_comp
|
||||
template <typename Variant, typename Comp>
|
||||
class comparer
|
||||
{
|
||||
public:
|
||||
public:
|
||||
explicit comparer(Variant const& lhs) noexcept
|
||||
: lhs_(lhs) {}
|
||||
comparer& operator=(comparer const&) = delete;
|
||||
@ -527,26 +525,22 @@ class comparer
|
||||
template <typename T>
|
||||
bool operator()(T const& rhs_content) const
|
||||
{
|
||||
T const& lhs_content = lhs_.template get<T>();
|
||||
T const& lhs_content = lhs_.template get_unchecked<T>();
|
||||
return Comp()(lhs_content, rhs_content);
|
||||
}
|
||||
|
||||
private:
|
||||
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>>
|
||||
// hashing visitor
|
||||
struct hasher
|
||||
{
|
||||
template <typename T>
|
||||
std::size_t operator()(const T& hashable) const
|
||||
{
|
||||
return std::hash<T>{}(hashable);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@ -559,20 +553,23 @@ 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?");
|
||||
static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?");
|
||||
|
||||
private:
|
||||
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;
|
||||
public:
|
||||
struct adapted_variant_tag;
|
||||
using types = std::tuple<Types...>;
|
||||
private:
|
||||
using first_type = typename std::tuple_element<0, 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:
|
||||
public:
|
||||
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
|
||||
: type_index(sizeof...(Types)-1)
|
||||
{
|
||||
@ -585,7 +582,7 @@ class variant
|
||||
|
||||
// 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>
|
||||
typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
|
||||
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
|
||||
: type_index(Traits::index)
|
||||
{
|
||||
@ -598,13 +595,13 @@ class variant
|
||||
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)
|
||||
VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<types>::value)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::move(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
@ -621,7 +618,7 @@ class variant
|
||||
type_index = rhs.type_index;
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
|
||||
{
|
||||
move_assign(std::move(other));
|
||||
@ -653,13 +650,20 @@ class variant
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
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;
|
||||
}
|
||||
|
||||
template <typename T,typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE bool is() const
|
||||
{
|
||||
return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool valid() const
|
||||
{
|
||||
return type_index != detail::invalid_value;
|
||||
@ -674,9 +678,18 @@ class variant
|
||||
type_index = detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
// get_unchecked<T>()
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get_unchecked()
|
||||
{
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// get<T>()
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
@ -688,9 +701,18 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return *reinterpret_cast<T const*>(&data);
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
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)
|
||||
@ -702,10 +724,20 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// get_unchecked<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_unchecked()
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// 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>
|
||||
(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)
|
||||
@ -717,9 +749,18 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
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)
|
||||
@ -731,10 +772,20 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// get_unchecked<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_unchecked()
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// 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>
|
||||
(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)
|
||||
@ -746,9 +797,18 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
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)
|
||||
@ -760,6 +820,7 @@ class variant
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function is deprecated because it returns an internal index field.
|
||||
// Use which() instead.
|
||||
@ -773,6 +834,13 @@ class variant
|
||||
return static_cast<int>(sizeof...(Types)-type_index - 1);
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE static constexpr int which() noexcept
|
||||
{
|
||||
return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1);
|
||||
}
|
||||
|
||||
// visitor
|
||||
// unary
|
||||
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
|
||||
@ -805,6 +873,22 @@ class variant
|
||||
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// match
|
||||
// unary
|
||||
template <typename... Fs>
|
||||
auto VARIANT_INLINE match(Fs&&... fs) const
|
||||
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
|
||||
{
|
||||
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
|
||||
}
|
||||
// non-const
|
||||
template <typename... Fs>
|
||||
auto VARIANT_INLINE match(Fs&&... fs)
|
||||
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
|
||||
{
|
||||
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
|
||||
}
|
||||
|
||||
~variant() noexcept // no-throw destructor
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
@ -884,18 +968,46 @@ auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_vis
|
||||
}
|
||||
|
||||
// getter interface
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename ResultType, typename T>
|
||||
ResultType& get(T& var)
|
||||
auto get(T& var)->decltype(var.template get<ResultType>())
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ResultType, typename T>
|
||||
ResultType const& get(T const& var)
|
||||
ResultType& get_unchecked(T& var)
|
||||
{
|
||||
return var.template get_unchecked<ResultType>();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename ResultType, typename T>
|
||||
auto get(T const& var)->decltype(var.template get<ResultType>())
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ResultType, typename T>
|
||||
ResultType const& get_unchecked(T const& var)
|
||||
{
|
||||
return var.template get_unchecked<ResultType>();
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
// hashable iff underlying types are hashable
|
||||
namespace std {
|
||||
template <typename... Types>
|
||||
struct hash< ::mapbox::util::variant<Types...>> {
|
||||
std::size_t operator()(const ::mapbox::util::variant<Types...>& v) const noexcept
|
||||
{
|
||||
return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_HPP
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
@ -13,7 +13,7 @@ namespace detail {
|
||||
template <typename Out>
|
||||
class printer
|
||||
{
|
||||
public:
|
||||
public:
|
||||
explicit printer(Out& out)
|
||||
: out_(out) {}
|
||||
printer& operator=(printer const&) = delete;
|
||||
@ -25,7 +25,7 @@ class printer
|
||||
out_ << operand;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
Out& out_;
|
||||
};
|
||||
}
|
38
third_party/variant/include/mapbox/variant_visitor.hpp
vendored
Normal file
38
third_party/variant/include/mapbox/variant_visitor.hpp
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_VISITOR_HPP
|
||||
|
||||
namespace mapbox {
|
||||
namespace util {
|
||||
|
||||
template <typename... Fns>
|
||||
struct visitor;
|
||||
|
||||
template <typename Fn>
|
||||
struct visitor<Fn> : Fn
|
||||
{
|
||||
using type = Fn;
|
||||
using Fn::operator();
|
||||
|
||||
visitor(Fn fn) : Fn(fn) {}
|
||||
};
|
||||
|
||||
template <typename Fn, typename... Fns>
|
||||
struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
|
||||
{
|
||||
using type = visitor;
|
||||
using Fn::operator();
|
||||
using visitor<Fns...>::operator();
|
||||
|
||||
visitor(Fn fn, Fns... fns) : Fn(fn), visitor<Fns...>(fns...) {}
|
||||
};
|
||||
|
||||
template <typename... Fns>
|
||||
visitor<Fns...> make_visitor(Fns... fns)
|
||||
{
|
||||
return visitor<Fns...>(fns...);
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP
|
@ -14,7 +14,7 @@ fi
|
||||
|
||||
error_msg() {
|
||||
if [ ! -z "$1" ]; then
|
||||
printf 'output was:\n=======\n%s\n=======\n' "$1"
|
||||
printf 'output was:\n=======\n%s\n=======\n' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
@ -22,29 +22,28 @@ 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`
|
||||
result=`${CXX} -std=c++11 -c -o /dev/null -I./include ${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
|
||||
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
|
||||
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
|
||||
echo "$name [FAILED - unknown error in compile]"
|
||||
error_msg "$result"
|
||||
exit_code=1
|
||||
fi
|
||||
done
|
||||
|
||||
exit ${exit_code}
|
||||
|
||||
|
15
third_party/variant/test/bench_variant.cpp
vendored
15
third_party/variant/test/bench_variant.cpp
vendored
@ -1,4 +1,3 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
@ -8,10 +7,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include "auto_cpu_timer.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <boost/variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define TEXT_SHORT "Test"
|
||||
#define TEXT_LONG "Testing various variant implementations with a longish string ........................................."
|
||||
@ -140,12 +139,12 @@ int main(int argc, char** argv)
|
||||
|
||||
{
|
||||
std::cerr << "custom variant: ";
|
||||
boost::timer::auto_cpu_timer t;
|
||||
auto_cpu_timer t;
|
||||
run_variant_test(NUM_RUNS);
|
||||
}
|
||||
{
|
||||
std::cerr << "boost variant: ";
|
||||
boost::timer::auto_cpu_timer t;
|
||||
auto_cpu_timer t;
|
||||
run_boost_test(NUM_RUNS);
|
||||
}
|
||||
}
|
||||
@ -158,7 +157,7 @@ int main(int argc, char** argv)
|
||||
typedef thread_group::value_type value_type;
|
||||
thread_group tg;
|
||||
std::cerr << "custom variant: ";
|
||||
boost::timer::auto_cpu_timer 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));
|
||||
@ -171,7 +170,7 @@ int main(int argc, char** argv)
|
||||
typedef thread_group::value_type value_type;
|
||||
thread_group tg;
|
||||
std::cerr << "boost variant: ";
|
||||
boost::timer::auto_cpu_timer 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));
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED: First type in variant must be default constructible to allow default construction of variant
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
// Checks that the first type in a variant must be default constructible to
|
||||
// make the variant default constructible.
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED: Template parameter type list of variant can not be empty
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
// Empty type list should not work.
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED:
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED: enable_if
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
// @EXPECTED:
|
||||
|
||||
// @EXPECTED: invalid type in T in `is<T>()` for this variant
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED: const int
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
struct mutating_visitor
|
||||
{
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
// @EXPECTED: Variant can not hold reference types
|
||||
|
||||
#include <variant.hpp>
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
|
158
third_party/variant/test/hashable_test.cpp
vendored
Normal file
158
third_party/variant/test/hashable_test.cpp
vendored
Normal file
@ -0,0 +1,158 @@
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
using namespace mapbox::util;
|
||||
|
||||
void test_singleton()
|
||||
{
|
||||
using V = variant<int>;
|
||||
|
||||
V singleton = 5;
|
||||
|
||||
if (std::hash<V>{}(singleton) != std::hash<int>{}(5))
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void test_default_hashable()
|
||||
{
|
||||
using V = variant<int, double, std::string>;
|
||||
|
||||
V var;
|
||||
|
||||
// Check int hashes
|
||||
var = 1;
|
||||
|
||||
if (std::hash<V>{}(var) != std::hash<int>{}(1))
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Check double hashes
|
||||
var = 23.4;
|
||||
|
||||
if (std::hash<V>{}(var) != std::hash<double>{}(23.4))
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Check string hashes
|
||||
var = std::string{"Hello, World!"};
|
||||
|
||||
if (std::hash<V>{}(var) != std::hash<std::string>{}("Hello, World!"))
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
struct Hashable
|
||||
{
|
||||
static const constexpr auto const_hash = 5;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Hashable>
|
||||
{
|
||||
std::size_t operator()(const Hashable&) const noexcept
|
||||
{
|
||||
return Hashable::const_hash;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void test_custom_hasher()
|
||||
{
|
||||
using V = variant<int, Hashable, double>;
|
||||
|
||||
V var;
|
||||
|
||||
var = Hashable{};
|
||||
|
||||
if (std::hash<V>{}(var) != Hashable::const_hash)
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void test_hashable_in_container()
|
||||
{
|
||||
using V = variant<int, std::string, double>;
|
||||
|
||||
// won't compile if V is not Hashable
|
||||
std::unordered_set<V> vs;
|
||||
|
||||
vs.insert(1);
|
||||
vs.insert(2.3);
|
||||
vs.insert("4");
|
||||
}
|
||||
|
||||
struct Empty
|
||||
{
|
||||
};
|
||||
|
||||
struct Node;
|
||||
|
||||
using Tree = variant<Empty, recursive_wrapper<Node>>;
|
||||
|
||||
struct Node
|
||||
{
|
||||
Node(Tree left_, Tree right_) : left(std::move(left_)), right(std::move(right_)) {}
|
||||
|
||||
Tree left = Empty{};
|
||||
Tree right = Empty{};
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Empty>
|
||||
{
|
||||
std::size_t operator()(const Empty&) const noexcept
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<Node>
|
||||
{
|
||||
std::size_t operator()(const Node& n) const noexcept
|
||||
{
|
||||
return 5 + std::hash<Tree>{}(n.left) + std::hash<Tree>{}(n.right);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void test_recursive_hashable()
|
||||
{
|
||||
|
||||
Tree tree = Node{Node{Empty{}, Empty{}}, Empty{}};
|
||||
|
||||
if (std::hash<Tree>{}(tree) != ((5 + (5 + (3 + 3))) + 3))
|
||||
{
|
||||
std::cerr << "Expected variant hash to be the same as hash of its value\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_singleton();
|
||||
test_default_hashable();
|
||||
test_custom_hasher();
|
||||
test_hashable_in_container();
|
||||
test_recursive_hashable();
|
||||
}
|
16
third_party/variant/test/include/auto_cpu_timer.hpp
vendored
Normal file
16
third_party/variant/test/include/auto_cpu_timer.hpp
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
struct auto_cpu_timer {
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> start;
|
||||
auto_cpu_timer() : start(std::chrono::high_resolution_clock::now()) {
|
||||
}
|
||||
~auto_cpu_timer() {
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
std::chrono::microseconds elapsed =
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
std::cerr << elapsed.count() << "us" << std::endl;
|
||||
}
|
||||
};
|
127
third_party/variant/test/lambda_overload_test.cpp
vendored
Normal file
127
third_party/variant/test/lambda_overload_test.cpp
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_visitor.hpp>
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
#define HAS_CPP14_SUPPORT
|
||||
#endif
|
||||
|
||||
using namespace mapbox::util;
|
||||
|
||||
template <typename Left, typename Right>
|
||||
using Either = mapbox::util::variant<Left, Right>;
|
||||
|
||||
struct Response
|
||||
{
|
||||
};
|
||||
|
||||
struct Error
|
||||
{
|
||||
};
|
||||
|
||||
void test_lambda_overloads()
|
||||
{
|
||||
Either<Error, Response> rv;
|
||||
|
||||
rv = Response{};
|
||||
|
||||
auto visitor = make_visitor([](Response) { std::cout << "Response\n"; }, //
|
||||
[](Error) { std::cout << "Error\n"; }); //
|
||||
apply_visitor(visitor, rv);
|
||||
}
|
||||
|
||||
void test_lambda_overloads_capture()
|
||||
{
|
||||
Either<Error, Response> rv;
|
||||
|
||||
rv = Error{};
|
||||
|
||||
int ok = 0;
|
||||
int err = 0;
|
||||
|
||||
auto visitor = make_visitor([&](Response) { ok += 1; }, //
|
||||
[&](Error) { err += 1; }); //
|
||||
apply_visitor(visitor, rv);
|
||||
|
||||
std::cout << "Got " << ok << " ok, " << err << " err" << std::endl;
|
||||
}
|
||||
|
||||
void test_singleton_variant()
|
||||
{
|
||||
|
||||
variant<int> singleton;
|
||||
apply_visitor(make_visitor([](int) {}), singleton);
|
||||
}
|
||||
|
||||
void test_lambda_overloads_sfinae()
|
||||
#ifdef HAS_CPP14_SUPPORT
|
||||
{
|
||||
variant<int, float, std::vector<int>> var;
|
||||
|
||||
auto visitor = make_visitor([](auto range) -> decltype(std::begin(range), void()) {
|
||||
for (auto each : range)
|
||||
std::cout << each << ' '; },
|
||||
[](auto x) -> decltype(std::cout << x, void()) {
|
||||
std::cout << x << std::endl;
|
||||
});
|
||||
|
||||
var = 1;
|
||||
apply_visitor(visitor, var);
|
||||
|
||||
var = 2.f;
|
||||
apply_visitor(visitor, var);
|
||||
|
||||
var = std::vector<int>{4, 5, 6};
|
||||
apply_visitor(visitor, var);
|
||||
}
|
||||
#else
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_match_singleton()
|
||||
{
|
||||
variant<int> singleton = 5;
|
||||
singleton.match([](int) {});
|
||||
}
|
||||
|
||||
void test_match_overloads()
|
||||
{
|
||||
Either<Error, Response> rv;
|
||||
|
||||
rv = Response{};
|
||||
|
||||
rv.match([](Response) { std::cout << "Response\n"; }, //
|
||||
[](Error) { std::cout << "Error\n"; }); //
|
||||
}
|
||||
|
||||
void test_match_overloads_capture()
|
||||
{
|
||||
Either<Error, Response> rv;
|
||||
|
||||
rv = Error{};
|
||||
|
||||
int ok = 0;
|
||||
int err = 0;
|
||||
|
||||
rv.match([&](Response) { ok += 1; }, //
|
||||
[&](Error) { err += 1; }); //
|
||||
|
||||
std::cout << "Got " << ok << " ok, " << err << " err" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_lambda_overloads();
|
||||
test_singleton_variant();
|
||||
test_lambda_overloads_capture();
|
||||
test_lambda_overloads_sfinae();
|
||||
|
||||
test_match_singleton();
|
||||
test_match_overloads();
|
||||
test_match_overloads_capture();
|
||||
}
|
||||
|
||||
#undef HAS_CPP14_SUPPORT
|
@ -1,4 +1,4 @@
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include "auto_cpu_timer.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
@ -111,7 +111,7 @@ int main(int argc, char** argv)
|
||||
|
||||
int total = 0;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
auto_cpu_timer t;
|
||||
for (std::size_t i = 0; i < NUM_ITER; ++i)
|
||||
{
|
||||
total += util::apply_visitor(test::calculator(), result);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
@ -41,9 +41,12 @@ struct print
|
||||
void operator()(line_string const& line) const
|
||||
{
|
||||
std::cerr << "Line(";
|
||||
bool first = true;
|
||||
for (auto const& pt : line)
|
||||
{
|
||||
std::cerr << pt.x << " " << pt.y << ",";
|
||||
if (!first) std::cerr << ",";
|
||||
std::cerr << pt.x << " " << pt.y;
|
||||
if (first) first = false;
|
||||
}
|
||||
std::cerr << ")" << std::endl;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " i-d"
|
||||
using variant_type = mapbox::util::variant<int, double>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " b-i-d"
|
||||
using variant_type = mapbox::util::variant<bool, int, double>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " i-d-b"
|
||||
using variant_type = mapbox::util::variant<int, double, bool>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " b-i-d-c"
|
||||
using variant_type = mapbox::util::variant<bool, int, double, char>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " b-i-c-d-i"
|
||||
using variant_type = mapbox::util::variant<bool, int, char, double, int>;
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
#define NAME_EXT " b-i-i-d-c-u"
|
||||
using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
struct add_visitor
|
||||
{
|
||||
|
20
third_party/variant/test/t/issue122.cpp
vendored
Normal file
20
third_party/variant/test/t/issue122.cpp
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
// https://github.com/mapbox/variant/issues/122
|
||||
|
||||
struct X
|
||||
{
|
||||
template <typename ValueType>
|
||||
X(const ValueType&) {}
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE("Correctly choose appropriate constructor", "[variant]")
|
||||
{
|
||||
mapbox::util::variant<X, int> a{123};
|
||||
decltype(a) b(a);
|
||||
REQUIRE(a.which() == b.which());
|
||||
}
|
14
third_party/variant/test/t/issue21.cpp
vendored
14
third_party/variant/test/t/issue21.cpp
vendored
@ -1,8 +1,7 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
// https://github.com/mapbox/variant/issues/21
|
||||
|
||||
@ -11,6 +10,12 @@ static int count;
|
||||
struct t1
|
||||
{
|
||||
int value;
|
||||
|
||||
t1(t1 const& rhs)
|
||||
: value(rhs.value)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
t1(int v) : value(v)
|
||||
{
|
||||
++count;
|
||||
@ -37,7 +42,8 @@ TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
|
||||
|
||||
count = 0;
|
||||
{
|
||||
variant_type v{42};
|
||||
t1 obj{42};
|
||||
variant_type v = obj;
|
||||
REQUIRE(v.is<t1>());
|
||||
REQUIRE(v.get<t1>().value == 42);
|
||||
REQUIRE_THROWS({
|
||||
|
@ -1,8 +1,8 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
2
third_party/variant/test/t/optional.cpp
vendored
2
third_party/variant/test/t/optional.cpp
vendored
@ -1,7 +1,7 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "optional.hpp"
|
||||
#include <mapbox/optional.hpp>
|
||||
|
||||
struct dummy
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "recursive_wrapper.hpp"
|
||||
#include <mapbox/recursive_wrapper.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
4
third_party/variant/test/t/sizeof.cpp
vendored
4
third_party/variant/test/t/sizeof.cpp
vendored
@ -5,8 +5,8 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
struct some_struct
|
||||
{
|
||||
|
4
third_party/variant/test/t/unary_visitor.cpp
vendored
4
third_party/variant/test/t/unary_visitor.cpp
vendored
@ -1,8 +1,8 @@
|
||||
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
33
third_party/variant/test/t/variant.cpp
vendored
33
third_party/variant/test/t/variant.cpp
vendored
@ -1,7 +1,7 @@
|
||||
#include "catch.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include "variant_io.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
#include <mapbox/variant_io.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@ -325,7 +325,7 @@ TEST_CASE("implicit conversion", "[variant][implicit conversion]")
|
||||
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
|
||||
variant_type var = 5l; // converted to long
|
||||
REQUIRE(var.get<long>() == 5);
|
||||
REQUIRE_THROWS_AS({
|
||||
var.get<char>();
|
||||
@ -543,9 +543,9 @@ TEST_CASE("storing reference wrappers to consts works")
|
||||
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(v.get<int>() == 1);
|
||||
REQUIRE(mapbox::util::get<int const>(v) == 1);
|
||||
// REQUIRE(mapbox::util::get<int>(v) == 1); // this doesn't work (see #82)
|
||||
REQUIRE(mapbox::util::get<int>(v) == 1);
|
||||
REQUIRE_THROWS_AS({
|
||||
v.get<double const>();
|
||||
},
|
||||
@ -568,3 +568,26 @@ TEST_CASE("storing reference wrappers to consts works")
|
||||
},
|
||||
mapbox::util::bad_variant_access&);
|
||||
}
|
||||
|
||||
TEST_CASE("recursive wrapper")
|
||||
{
|
||||
using variant_type = mapbox::util::variant<mapbox::util::recursive_wrapper<int>>;
|
||||
variant_type v(1);
|
||||
REQUIRE(v.is<int>());
|
||||
REQUIRE(v.get<int>() == 1);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("variant : direct_type helper should match T, references (T&) and const references (T const&) to the original type T)")
|
||||
{
|
||||
using value = mapbox::util::variant<bool, std::uint64_t>;
|
||||
|
||||
std::uint64_t u(1234);
|
||||
REQUIRE(value(u).is<std::uint64_t>()); // matches T
|
||||
|
||||
std::uint64_t& ur(u);
|
||||
REQUIRE(value(ur).is<std::uint64_t>()); // matches T&
|
||||
|
||||
std::uint64_t const& ucr(u);
|
||||
REQUIRE(value(ucr).is<std::uint64_t>()); // matches T const&
|
||||
}
|
||||
|
6
third_party/variant/test/unique_ptr_test.cpp
vendored
6
third_party/variant/test/unique_ptr_test.cpp
vendored
@ -6,9 +6,9 @@
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include "auto_cpu_timer.hpp"
|
||||
|
||||
#include "variant.hpp"
|
||||
#include <mapbox/variant.hpp>
|
||||
|
||||
using namespace mapbox;
|
||||
|
||||
@ -112,7 +112,7 @@ int main(int argc, char** argv)
|
||||
|
||||
int total = 0;
|
||||
{
|
||||
boost::timer::auto_cpu_timer t;
|
||||
auto_cpu_timer t;
|
||||
for (std::size_t i = 0; i < NUM_ITER; ++i)
|
||||
{
|
||||
total += util::apply_visitor(test::calculator(), result);
|
||||
|
2
third_party/variant/variant.gyp
vendored
2
third_party/variant/variant.gyp
vendored
@ -27,7 +27,7 @@
|
||||
"SUPPORTED_PLATFORMS":["macosx"]
|
||||
},
|
||||
"include_dirs": [
|
||||
"./",
|
||||
"./include",
|
||||
"test/include"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user