Upgrade to mapbox/variant 1.1.4

This commit is contained in:
Daniel Patterson 2016-12-01 15:44:27 -08:00
parent 20c8ac0272
commit 29b3caf529
44 changed files with 936 additions and 286 deletions

View File

@ -6,3 +6,4 @@ deps
*.gcda *.gcda
*.gcno *.gcno
.ycm_extra_conf.pyc .ycm_extra_conf.pyc
mason_packages

3
third_party/variant/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule ".mason"]
path = .mason
url = https://github.com/mapbox/mason.git

View File

@ -1,4 +1,4 @@
language: c language: generic
sudo: false sudo: false
@ -6,49 +6,50 @@ sudo: false
addons_shortcuts: addons_shortcuts:
addons_clang35: &clang35 addons_clang35: &clang35
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
packages: [ 'clang-3.5', 'libboost1.55-all-dev' ] packages: [ 'clang-3.5', 'llvm-3.5-dev' ]
addons_clang36: &clang36 addons_clang36: &clang36
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6' ]
packages: [ 'clang-3.6', 'libboost1.55-all-dev' ] packages: [ 'clang-3.6' ]
addons_clang37: &clang37 addons_clang37: &clang37
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7' ]
packages: [ 'clang-3.7', 'libboost1.55-all-dev' ] packages: [ 'clang-3.7' ]
addons_clang38: &clang38 addons_clang38: &clang38
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.8' ]
packages: [ 'clang-3.8', 'libboost1.55-all-dev'] packages: [ 'clang-3.8']
addons_clang39: &clang39
apt:
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise' ]
packages: [ 'clang-3.9']
addons_gcc47: &gcc47 addons_gcc47: &gcc47
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'g++-4.7', 'libboost1.55-all-dev' ] packages: [ 'g++-4.7' ]
addons_gcc48: &gcc48 addons_gcc48: &gcc48
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'g++-4.8', 'libboost1.55-all-dev' ] packages: [ 'g++-4.8' ]
addons_gcc49: &gcc49 addons_gcc49: &gcc49
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'g++-4.9', 'libboost1.55-all-dev' ] packages: [ 'g++-4.9' ]
addons_gcc5: &gcc5 addons_gcc5: &gcc5
apt: apt:
sources: [ 'ubuntu-toolchain-r-test', 'boost-latest' ] sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'g++-5', 'libboost1.55-all-dev' ] packages: [ 'g++-5' ]
matrix: matrix:
include: include:
- os: osx
osx_image: xcode6
compiler: clang
- os: osx - os: osx
osx_image: xcode7 osx_image: xcode7
env: TEST_GYP_BUILD=True env: TEST_GYP_BUILD=True
compiler: clang compiler: clang
- os: linux - os: linux
compiler: "clang35" compiler: "clang35"
env: CXX=clang++-3.5 env: CXX=clang++-3.5 COVERAGE=True
addons: *clang35 addons: *clang35
- os: linux - os: linux
compiler: "clang36" compiler: "clang36"
@ -56,7 +57,7 @@ matrix:
addons: *clang36 addons: *clang36
- os: linux - os: linux
compiler: "clang37" compiler: "clang37"
env: CXX=clang++-3.7 COVERAGE=True env: CXX=clang++-3.7
addons: *clang37 addons: *clang37
- os: linux - os: linux
compiler: "clang38" compiler: "clang38"
@ -66,6 +67,11 @@ matrix:
compiler: "clang38" compiler: "clang38"
env: CXX=clang++-3.8 CXX_STD=c++14 env: CXX=clang++-3.8 CXX_STD=c++14
addons: *clang38 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 - os: linux
compiler: "gcc47" compiler: "gcc47"
env: CXX=g++-4.7 env: CXX=g++-4.7
@ -96,7 +102,6 @@ before_install:
- if [[ $(uname -s) == 'Linux' ]]; then - if [[ $(uname -s) == 'Linux' ]]; then
export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages; export PYTHONPATH=$(pwd)/.local/lib/python2.7/site-packages;
else else
brew install boost;
export PYTHONPATH=$(pwd)/.local/lib/python/site-packages; export PYTHONPATH=$(pwd)/.local/lib/python/site-packages;
fi fi
- if [[ ${COVERAGE:-0} == 'True' ]]; then - if [[ ${COVERAGE:-0} == 'True' ]]; then
@ -106,11 +111,7 @@ before_install:
install: install:
- make test - make test
- make bench - make bench
- if [[ $(uname -s) == 'Linux' ]]; then - make sizes
make sizes /usr/include/boost/variant.hpp;
else
make sizes `brew --prefix`/include/boost/variant.hpp;
fi
- scripts/run_compilation_failure_tests.sh - scripts/run_compilation_failure_tests.sh
- if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then - if [[ ${TEST_GYP_BUILD:-0} == 'True' ]]; then
make clean; make clean;
@ -123,5 +124,5 @@ script:
make coverage; make coverage;
./out/cov-test; ./out/cov-test;
cp unit*gc* 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 fi

View File

@ -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. # You should use make unless you know what you are doing.
local BOOST_DIR = "/usr/local" ; local BOOST_DIR = "/usr/local" ;
@ -17,9 +17,10 @@ exe variant-test
.//chrono .//chrono
: :
<include>$(BOOST_DIR)/include <include>$(BOOST_DIR)/include
<include>./ <include>./include
<include>./test/include
#<define>SINGLE_THREADED #<define>SINGLE_THREADED
<variant>release:<cxxflags>-march=native <variant>release:<cxxflags>"-march=native -Wweak-vtables"
; ;
@ -31,7 +32,8 @@ exe binary-visitor-test
.//chrono .//chrono
: :
<include>$(BOOST_DIR)/include <include>$(BOOST_DIR)/include
<include>./ <include>./include
<include>./test/include
<variant>release:<cxxflags>-march=native <variant>release:<cxxflags>-march=native
; ;
@ -43,7 +45,8 @@ exe recursive-wrapper-test
.//chrono .//chrono
: :
<include>$(BOOST_DIR)/include <include>$(BOOST_DIR)/include
<include>./ <include>./include
<include>./test/include
<variant>release:<cxxflags>-march=native <variant>release:<cxxflags>-march=native
; ;
@ -55,7 +58,8 @@ exe unique-ptr-test
.//chrono .//chrono
: :
<include>$(BOOST_DIR)/include <include>$(BOOST_DIR)/include
<include>./ <include>./include
<include>./test/include
<variant>release:<cxxflags>-march=native <variant>release:<cxxflags>-march=native
; ;
@ -68,6 +72,7 @@ exe reference_wrapper_test
.//chrono .//chrono
: :
<include>$(BOOST_DIR)/include <include>$(BOOST_DIR)/include
<include>./ <include>./include
<include>./test/include
<variant>release:<cxxflags>-march=native <variant>release:<cxxflags>-march=native
; ;

View File

@ -1,32 +1,23 @@
MASON = .mason/mason
BOOST_VERSION = boost 1.60.0
CXX := $(CXX) CXX := $(CXX)
CXX_STD ?= c++11 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 RELEASE_FLAGS = -O3 -DNDEBUG -march=native -DSINGLE_THREADED -fvisibility-inlines-hidden
DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD) COMMON_FLAGS = -Wall -pedantic -Wextra -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -std=$(CXX_STD)
CXXFLAGS := $(CXXFLAGS) CXXFLAGS := $(CXXFLAGS)
LDFLAGS := $(LDFLAGS) LDFLAGS := $(LDFLAGS)
OS:=$(shell uname -s) ALL_HEADERS = $(shell find include/mapbox/ '(' -name '*.hpp' ')')
ifeq ($(OS),Darwin)
CXXFLAGS += -stdlib=libc++
LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
else
BOOST_LIBS += -lrt
endif
ifeq (sizes,$(firstword $(MAKECMDGOALS))) 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
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 mason_packages:
git submodule update --init .mason
$(MASON) install $(BOOST_VERSION)
./deps/gyp: ./deps/gyp:
git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./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 make V=1 -C ./out tests
./out/Release/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 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 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 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 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 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 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/bench-variant 100000
@ -66,11 +65,11 @@ out/unit.o: Makefile test/unit.cpp
mkdir -p ./out mkdir -p ./out
$(CXX) -c -o $@ test/unit.cpp -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(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 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 mkdir -p ./out
$(CXX) -o $@ $^ $(LDFLAGS) $(CXX) -o $@ $^ $(LDFLAGS)
@ -79,14 +78,14 @@ test: out/unit
coverage: coverage:
mkdir -p ./out 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 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/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 $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_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./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/our_variant_hello_world @$(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./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_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 profile: out/bench-variant-debug
mkdir -p profiling/ mkdir -p profiling/
@ -102,9 +101,9 @@ clean:
rm -f test/*gcov rm -f test/*gcov
rm -f *.gcda *.gcno rm -f *.gcda *.gcno
pgo: out Makefile variant.hpp recursive_wrapper.hpp pgo: out Makefile
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate $(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 ./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 .PHONY: sizes test

View File

@ -1,11 +1,169 @@
# Mapbox Variant # Mapbox Variant
An alternative to `boost::variant` for C++11. An header-only alternative to `boost::variant` for C++11 and C++14
[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant) [![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant) [![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master) [![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](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? ## 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 Want to know more about the upcoming standard? Have a look at our
[overview](doc/standards_effort.md). [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 ## Depends
@ -55,19 +216,14 @@ Tested with:
- g++-4.7 - g++-4.7
- g++-4.8 - g++-4.8
- g++-4.9 - g++-4.9
- g++-5 - g++-5.2
- clang++-3.5 - clang++-3.5
- clang++-3.6 - clang++-3.6
- clang++-3.7 - clang++-3.7
- clang++-3.8 - clang++-3.8
- clang++-3.9
- Visual Studio 2015 - 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 ## Unit Tests
@ -93,15 +249,6 @@ On Windows run `scripts/build-local.bat`.
## Benchmarks ## 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 make bench

View File

@ -6,7 +6,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "variant.hpp" #include <mapbox/variant.hpp>
namespace mapbox { namespace mapbox {
namespace util { namespace util {

View File

@ -42,9 +42,9 @@ class recursive_wrapper
* @throws any exception thrown by the default constructur of T. * @throws any exception thrown by the default constructur of T.
*/ */
recursive_wrapper() recursive_wrapper()
: p_(new T){}; : p_(new T){}
~recursive_wrapper() noexcept { delete p_; }; ~recursive_wrapper() noexcept { delete p_; }
recursive_wrapper(recursive_wrapper const& operand) recursive_wrapper(recursive_wrapper const& operand)
: p_(new T(operand.get())) {} : p_(new T(operand.get())) {}

View File

@ -10,8 +10,10 @@
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <utility> #include <utility>
#include <functional>
#include "recursive_wrapper.hpp" #include <mapbox/recursive_wrapper.hpp>
#include <mapbox/variant_visitor.hpp>
// clang-format off // clang-format off
// [[deprecated]] is only available in C++14, use this for the time being // [[deprecated]] is only available in C++14, use this for the time being
@ -33,17 +35,22 @@
# ifdef NDEBUG # ifdef NDEBUG
# define VARIANT_INLINE __forceinline # define VARIANT_INLINE __forceinline
# else # else
#define VARIANT_INLINE __declspec(noinline) # define VARIANT_INLINE //__declspec(noinline)
# endif # endif
#else #else
# ifdef NDEBUG # ifdef NDEBUG
#define VARIANT_INLINE inline __attribute__((always_inline)) # define VARIANT_INLINE //inline __attribute__((always_inline))
# else # else
# define VARIANT_INLINE __attribute__((noinline)) # define VARIANT_INLINE __attribute__((noinline))
# endif # endif
#endif #endif
// clang-format on // clang-format on
// Exceptions
#if defined( __EXCEPTIONS) || defined( _MSC_VER)
#define HAS_EXCEPTIONS
#endif
#define VARIANT_MAJOR_VERSION 1 #define VARIANT_MAJOR_VERSION 1
#define VARIANT_MINOR_VERSION 1 #define VARIANT_MINOR_VERSION 1
#define VARIANT_PATCH_VERSION 0 #define VARIANT_PATCH_VERSION 0
@ -98,6 +105,26 @@ struct direct_type<T>
static constexpr std::size_t index = invalid_value; 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> template <typename T, typename... Types>
struct convertible_type; struct convertible_type;
@ -105,7 +132,7 @@ template <typename T, typename First, typename... Types>
struct convertible_type<T, First, Types...> struct convertible_type<T, First, Types...>
{ {
static constexpr std::size_t index = std::is_convertible<T, First>::value static constexpr std::size_t index = std::is_convertible<T, First>::value
? sizeof...(Types) ? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
: convertible_type<T, Types...>::index; : convertible_type<T, Types...>::index;
}; };
@ -118,7 +145,7 @@ struct convertible_type<T>
template <typename T, typename... Types> template <typename T, typename... Types>
struct value_traits 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 std::size_t direct_index = direct_type<value_type, Types...>::index;
static constexpr bool is_direct = direct_index != invalid_value; 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 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; 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> template <typename T, typename R = void>
struct enable_if_type struct enable_if_type
{ {
@ -299,7 +297,7 @@ struct dispatcher<F, V, R, T, Types...>
{ {
if (v.template is<T>()) 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 else
{ {
@ -311,7 +309,7 @@ struct dispatcher<F, V, R, T, Types...>
{ {
if (v.template is<T>()) 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 else
{ {
@ -325,12 +323,12 @@ struct dispatcher<F, V, R, T>
{ {
VARIANT_INLINE static R apply_const(V const& v, F&& f) 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) 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 if (rhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()), return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>())); unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
} }
else else
{ {
@ -357,8 +355,8 @@ struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
{ {
if (rhs.template is<T1>()) // call binary functor if (rhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T0>::apply(lhs.template get<T0>()), return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>())); unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
} }
else 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) VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{ {
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()), return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>())); unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
} }
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{ {
return f(unwrapper<T0>::apply(lhs.template get<T0>()), return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>())); 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 if (lhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()), return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>())); unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
} }
else else
{ {
@ -406,8 +404,8 @@ struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
{ {
if (lhs.template is<T1>()) // call binary functor if (lhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T1>::apply(lhs.template get<T1>()), return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>())); unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
} }
else 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) VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{ {
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()), return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>())); unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
} }
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{ {
return f(unwrapper<T1>::apply(lhs.template get<T1>()), return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>())); 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>()) if (v1.template is<T>())
{ {
return f(unwrapper<T>::apply_const(v0.template get<T>()), return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
} }
else else
{ {
@ -465,8 +463,8 @@ struct binary_dispatcher<F, V, R, T, Types...>
{ {
if (v1.template is<T>()) if (v1.template is<T>())
{ {
return f(unwrapper<T>::apply(v0.template get<T>()), return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
} }
else 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) VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{ {
return f(unwrapper<T>::apply_const(v0.template get<T>()), return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
} }
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{ {
return f(unwrapper<T>::apply(v0.template get<T>()), return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
} }
}; };
@ -527,7 +525,7 @@ class comparer
template <typename T> template <typename T>
bool operator()(T const& rhs_content) const 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); return Comp()(lhs_content, rhs_content);
} }
@ -535,18 +533,14 @@ class comparer
Variant const& lhs_; Variant const& lhs_;
}; };
// True if Predicate matches for all of the types Ts // hashing visitor
template <template <typename> class Predicate, typename... Ts> struct hasher
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>>
{ {
}; template <typename T>
std::size_t operator()(const T& hashable) const
// 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>>
{ {
return std::hash<T>{}(hashable);
}
}; };
} // namespace detail } // namespace detail
@ -559,13 +553,16 @@ template <typename... Types>
class variant class variant
{ {
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty"); 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_size = detail::static_max<sizeof(Types)...>::value;
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value; static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
public:
using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type; 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 data_type = typename std::aligned_storage<data_size, data_align>::type;
using helper_type = detail::variant_helper<Types...>; using helper_type = detail::variant_helper<Types...>;
@ -585,7 +582,7 @@ class variant
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
template <typename T, typename Traits = detail::value_traits<T, Types...>, 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) VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
: type_index(Traits::index) : type_index(Traits::index)
{ {
@ -598,7 +595,7 @@ class variant
helper_type::copy(old.type_index, &old.data, &data); 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) : type_index(old.type_index)
{ {
helper_type::move(old.type_index, &old.data, &data); helper_type::move(old.type_index, &old.data, &data);
@ -653,13 +650,20 @@ class variant
return *this; 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 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; 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 VARIANT_INLINE bool valid() const
{ {
return type_index != detail::invalid_value; return type_index != detail::invalid_value;
@ -674,6 +678,15 @@ class variant
type_index = detail::direct_type<T, Types...>::index; 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>() // get<T>()
template <typename T, typename std::enable_if< 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>
@ -688,7 +701,16 @@ class variant
throw bad_variant_access("in get<T>()"); 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>
VARIANT_INLINE T const& get_unchecked() const
{
return *reinterpret_cast<T const*>(&data);
}
#ifdef HAS_EXCEPTIONS
template <typename T, typename std::enable_if< 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() const VARIANT_INLINE T const& get() const
@ -702,7 +724,17 @@ class variant
throw bad_variant_access("in get<T>()"); 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> // get<T>() - T stored as recursive_wrapper<T>
template <typename T, typename std::enable_if< 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>
@ -717,7 +749,16 @@ class variant
throw bad_variant_access("in get<T>()"); 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>
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< 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() const VARIANT_INLINE T const& get() const
@ -731,7 +772,17 @@ class variant
throw bad_variant_access("in get<T>()"); 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> // get<T>() - T stored as std::reference_wrapper<T>
template <typename T, typename std::enable_if< 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>
@ -746,7 +797,16 @@ class variant
throw bad_variant_access("in get<T>()"); 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>
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< 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() const VARIANT_INLINE T const& get() const
@ -760,6 +820,7 @@ class variant
throw bad_variant_access("in get<T>()"); throw bad_variant_access("in get<T>()");
} }
} }
#endif
// This function is deprecated because it returns an internal index field. // This function is deprecated because it returns an internal index field.
// Use which() instead. // Use which() instead.
@ -773,6 +834,13 @@ class variant
return static_cast<int>(sizeof...(Types)-type_index - 1); 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 // visitor
// unary // unary
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type> 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)); 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 ~variant() noexcept // no-throw destructor
{ {
helper_type::destroy(type_index, &data); 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 // getter interface
#ifdef HAS_EXCEPTIONS
template <typename ResultType, typename T> template <typename ResultType, typename T>
ResultType& get(T& var) auto get(T& var)->decltype(var.template get<ResultType>())
{ {
return var.template get<ResultType>(); return var.template get<ResultType>();
} }
#endif
template <typename ResultType, typename T> 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>(); 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 util
} // namespace mapbox } // 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 #endif // MAPBOX_UTIL_VARIANT_HPP

View File

@ -3,7 +3,7 @@
#include <iosfwd> #include <iosfwd>
#include "variant.hpp" #include <mapbox/variant.hpp>
namespace mapbox { namespace mapbox {
namespace util { namespace util {

View 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

View File

@ -22,7 +22,7 @@ exit_code=0
for test_code in $DIR/*.cpp; do for test_code in $DIR/*.cpp; do
name=`basename $test_code .cpp` 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=$? status=$?
if [ $status = 1 ]; then if [ $status = 1 ]; then
@ -47,4 +47,3 @@ for test_code in $DIR/*.cpp; do
done done
exit ${exit_code} exit ${exit_code}

View File

@ -1,4 +1,3 @@
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
@ -8,10 +7,10 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/timer/timer.hpp> #include "auto_cpu_timer.hpp"
#include <boost/variant.hpp>
#include "variant.hpp" #include <boost/variant.hpp>
#include <mapbox/variant.hpp>
#define TEXT_SHORT "Test" #define TEXT_SHORT "Test"
#define TEXT_LONG "Testing various variant implementations with a longish string ........................................." #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: "; std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer t; auto_cpu_timer t;
run_variant_test(NUM_RUNS); run_variant_test(NUM_RUNS);
} }
{ {
std::cerr << "boost variant: "; std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer t; auto_cpu_timer t;
run_boost_test(NUM_RUNS); run_boost_test(NUM_RUNS);
} }
} }
@ -158,7 +157,7 @@ int main(int argc, char** argv)
typedef thread_group::value_type value_type; typedef thread_group::value_type value_type;
thread_group tg; thread_group tg;
std::cerr << "custom variant: "; std::cerr << "custom variant: ";
boost::timer::auto_cpu_timer timer; auto_cpu_timer timer;
for (std::size_t i = 0; i < THREADS; ++i) for (std::size_t i = 0; i < THREADS; ++i)
{ {
tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS)); 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; typedef thread_group::value_type value_type;
thread_group tg; thread_group tg;
std::cerr << "boost variant: "; std::cerr << "boost variant: ";
boost::timer::auto_cpu_timer timer; auto_cpu_timer timer;
for (std::size_t i = 0; i < THREADS; ++i) for (std::size_t i = 0; i < THREADS; ++i)
{ {
tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS)); tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));

View File

@ -9,8 +9,8 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
using namespace mapbox; using namespace mapbox;

View File

@ -1,7 +1,6 @@
// @EXPECTED: First type in variant must be default constructible to allow default construction of variant // @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 // Checks that the first type in a variant must be default constructible to
// make the variant default constructible. // make the variant default constructible.

View File

@ -1,7 +1,6 @@
// @EXPECTED: Template parameter type list of variant can not be empty // @EXPECTED: Template parameter type list of variant can not be empty
#include <variant.hpp> #include <mapbox/variant.hpp>
// Empty type list should not work. // Empty type list should not work.

View File

@ -1,7 +1,6 @@
// @EXPECTED: // @EXPECTED:
#include <variant.hpp> #include <mapbox/variant.hpp>
int main() int main()
{ {

View File

@ -1,7 +1,6 @@
// @EXPECTED: enable_if // @EXPECTED: enable_if
#include <variant.hpp> #include <mapbox/variant.hpp>
int main() int main()
{ {

View File

@ -1,7 +1,6 @@
// @EXPECTED:
// @EXPECTED: invalid type in T in `is<T>()` for this variant #include <mapbox/variant.hpp>
#include <variant.hpp>
int main() int main()
{ {

View File

@ -1,7 +1,6 @@
// @EXPECTED: const int // @EXPECTED: const int
#include <variant.hpp> #include <mapbox/variant.hpp>
struct mutating_visitor struct mutating_visitor
{ {

View File

@ -1,7 +1,6 @@
// @EXPECTED: Variant can not hold reference types // @EXPECTED: Variant can not hold reference types
#include <variant.hpp> #include <mapbox/variant.hpp>
int main() int main()
{ {

View 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();
}

View 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;
}
};

View 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

View File

@ -1,4 +1,4 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#include <stdexcept> #include <stdexcept>

View File

@ -5,9 +5,9 @@
#include <typeinfo> #include <typeinfo>
#include <utility> #include <utility>
#include <boost/timer/timer.hpp> #include "auto_cpu_timer.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
using namespace mapbox; using namespace mapbox;
@ -111,7 +111,7 @@ int main(int argc, char** argv)
int total = 0; int total = 0;
{ {
boost::timer::auto_cpu_timer t; auto_cpu_timer t;
for (std::size_t i = 0; i < NUM_ITER; ++i) for (std::size_t i = 0; i < NUM_ITER; ++i)
{ {
total += util::apply_visitor(test::calculator(), result); total += util::apply_visitor(test::calculator(), result);

View File

@ -6,7 +6,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "variant.hpp" #include <mapbox/variant.hpp>
using namespace mapbox; using namespace mapbox;
@ -41,9 +41,12 @@ struct print
void operator()(line_string const& line) const void operator()(line_string const& line) const
{ {
std::cerr << "Line("; std::cerr << "Line(";
bool first = true;
for (auto const& pt : line) 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; std::cerr << ")" << std::endl;
} }

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " i-d" #define NAME_EXT " i-d"
using variant_type = mapbox::util::variant<int, double>; using variant_type = mapbox::util::variant<int, double>;

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " b-i-d" #define NAME_EXT " b-i-d"
using variant_type = mapbox::util::variant<bool, int, double>; using variant_type = mapbox::util::variant<bool, int, double>;

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " i-d-b" #define NAME_EXT " i-d-b"
using variant_type = mapbox::util::variant<int, double, bool>; using variant_type = mapbox::util::variant<int, double, bool>;

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " b-i-d-c" #define NAME_EXT " b-i-d-c"
using variant_type = mapbox::util::variant<bool, int, double, char>; using variant_type = mapbox::util::variant<bool, int, double, char>;

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " b-i-c-d-i" #define NAME_EXT " b-i-c-d-i"
using variant_type = mapbox::util::variant<bool, int, char, double, int>; using variant_type = mapbox::util::variant<bool, int, char, double, int>;

View File

@ -1,5 +1,5 @@
#include "variant.hpp" #include <mapbox/variant.hpp>
#define NAME_EXT " b-i-i-d-c-u" #define NAME_EXT " b-i-i-d-c-u"
using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>; using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;

View File

@ -3,7 +3,7 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
struct add_visitor struct add_visitor
{ {

20
third_party/variant/test/t/issue122.cpp vendored Normal file
View 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());
}

View File

@ -1,8 +1,7 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
// https://github.com/mapbox/variant/issues/21 // https://github.com/mapbox/variant/issues/21
@ -11,6 +10,12 @@ static int count;
struct t1 struct t1
{ {
int value; int value;
t1(t1 const& rhs)
: value(rhs.value)
{
++count;
}
t1(int v) : value(v) t1(int v) : value(v)
{ {
++count; ++count;
@ -37,7 +42,8 @@ TEST_CASE("set() works cleanly even if the constructor throws ", "[variant]")
count = 0; count = 0;
{ {
variant_type v{42}; t1 obj{42};
variant_type v = obj;
REQUIRE(v.is<t1>()); REQUIRE(v.is<t1>());
REQUIRE(v.get<t1>().value == 42); REQUIRE(v.get<t1>().value == 42);
REQUIRE_THROWS({ REQUIRE_THROWS({

View File

@ -1,8 +1,8 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
#include <string> #include <string>

View File

@ -1,7 +1,7 @@
#include "catch.hpp" #include "catch.hpp"
#include "optional.hpp" #include <mapbox/optional.hpp>
struct dummy struct dummy
{ {

View File

@ -1,7 +1,7 @@
#include "catch.hpp" #include "catch.hpp"
#include "recursive_wrapper.hpp" #include <mapbox/recursive_wrapper.hpp>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@ -5,8 +5,8 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
struct some_struct struct some_struct
{ {

View File

@ -1,8 +1,8 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
#include <string> #include <string>

View File

@ -1,7 +1,7 @@
#include "catch.hpp" #include "catch.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
#include "variant_io.hpp" #include <mapbox/variant_io.hpp>
#include <algorithm> #include <algorithm>
#include <cstdint> #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]") TEST_CASE("implicit conversion to first type in variant type list", "[variant][implicit conversion]")
{ {
using variant_type = mapbox::util::variant<long, char>; 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(var.get<long>() == 5);
REQUIRE_THROWS_AS({ REQUIRE_THROWS_AS({
var.get<char>(); var.get<char>();
@ -543,9 +543,9 @@ TEST_CASE("storing reference wrappers to consts works")
int a = 1; int a = 1;
variant_type v{std::cref(a)}; variant_type v{std::cref(a)};
REQUIRE(v.get<int const>() == 1); 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 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({ REQUIRE_THROWS_AS({
v.get<double const>(); v.get<double const>();
}, },
@ -568,3 +568,26 @@ TEST_CASE("storing reference wrappers to consts works")
}, },
mapbox::util::bad_variant_access&); 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&
}

View File

@ -6,9 +6,9 @@
#include <typeinfo> #include <typeinfo>
#include <utility> #include <utility>
#include <boost/timer/timer.hpp> #include "auto_cpu_timer.hpp"
#include "variant.hpp" #include <mapbox/variant.hpp>
using namespace mapbox; using namespace mapbox;
@ -112,7 +112,7 @@ int main(int argc, char** argv)
int total = 0; int total = 0;
{ {
boost::timer::auto_cpu_timer t; auto_cpu_timer t;
for (std::size_t i = 0; i < NUM_ITER; ++i) for (std::size_t i = 0; i < NUM_ITER; ++i)
{ {
total += util::apply_visitor(test::calculator(), result); total += util::apply_visitor(test::calculator(), result);

View File

@ -27,7 +27,7 @@
"SUPPORTED_PLATFORMS":["macosx"] "SUPPORTED_PLATFORMS":["macosx"]
}, },
"include_dirs": [ "include_dirs": [
"./", "./include",
"test/include" "test/include"
] ]
} }