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
*.gcno
.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
@ -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

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.
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
;

View File

@ -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

View File

@ -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
[![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)
[![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?
@ -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

View File

@ -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)

View File

@ -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())) {}

View File

@ -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

View File

@ -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_;
};
}

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

@ -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}

View File

@ -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));

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

@ -1,7 +1,6 @@
// @EXPECTED: Variant can not hold reference types
#include <variant.hpp>
#include <mapbox/variant.hpp>
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>

View File

@ -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);

View File

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

View File

@ -1,5 +1,5 @@
#include "variant.hpp"
#include <mapbox/variant.hpp>
#define NAME_EXT " i-d"
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"
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"
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"
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"
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"
using variant_type = mapbox::util::variant<bool, int, int, double, char, short int>;

View File

@ -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
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 "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({

View File

@ -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>

View File

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

View File

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

View File

@ -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
{

View File

@ -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>

View File

@ -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&
}

View File

@ -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);

View File

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