diff --git a/third_party/variant/.gitignore b/third_party/variant/.gitignore index a9bc8605e..e656256b6 100644 --- a/third_party/variant/.gitignore +++ b/third_party/variant/.gitignore @@ -6,3 +6,4 @@ deps *.gcda *.gcno .ycm_extra_conf.pyc +mason_packages diff --git a/third_party/variant/.gitmodules b/third_party/variant/.gitmodules new file mode 100644 index 000000000..44fba9a2f --- /dev/null +++ b/third_party/variant/.gitmodules @@ -0,0 +1,3 @@ +[submodule ".mason"] + path = .mason + url = https://github.com/mapbox/mason.git diff --git a/third_party/variant/.travis.yml b/third_party/variant/.travis.yml index 99d0b48c2..4119d9ef1 100644 --- a/third_party/variant/.travis.yml +++ b/third_party/variant/.travis.yml @@ -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 diff --git a/third_party/variant/Jamroot b/third_party/variant/Jamroot index 1e98cf555..3e863e25a 100644 --- a/third_party/variant/Jamroot +++ b/third_party/variant/Jamroot @@ -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 : $(BOOST_DIR)/include - ./ + ./include + ./test/include #SINGLE_THREADED - release:-march=native + release:"-march=native -Wweak-vtables" ; @@ -31,7 +32,8 @@ exe binary-visitor-test .//chrono : $(BOOST_DIR)/include - ./ + ./include + ./test/include release:-march=native ; @@ -43,7 +45,8 @@ exe recursive-wrapper-test .//chrono : $(BOOST_DIR)/include - ./ + ./include + ./test/include release:-march=native ; @@ -55,7 +58,8 @@ exe unique-ptr-test .//chrono : $(BOOST_DIR)/include - ./ + ./include + ./test/include release:-march=native ; @@ -68,6 +72,7 @@ exe reference_wrapper_test .//chrono : $(BOOST_DIR)/include - ./ + ./include + ./test/include release:-march=native ; diff --git a/third_party/variant/Makefile b/third_party/variant/Makefile index 36652511d..10ab7b5f0 100644 --- a/third_party/variant/Makefile +++ b/third_party/variant/Makefile @@ -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 diff --git a/third_party/variant/README.md b/third_party/variant/README.md index 24cdb570b..0e274b03b 100644 --- a/third_party/variant/README.md +++ b/third_party/variant/README.md @@ -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` - a type-safe representation for sum-types / discriminated unions +- `recursive_wrapper` - 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()` - 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; + +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 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, recursive_wrapper>; + +struct Array { + vector values; +}; + +struct Object { + unordered_map 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>; + +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; +using FilesystemResult = variant; + +// new type +struct APIResult : variant { + using Base = variant; + 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 diff --git a/third_party/variant/optional.hpp b/third_party/variant/include/mapbox/optional.hpp similarity index 97% rename from third_party/variant/optional.hpp rename to third_party/variant/include/mapbox/optional.hpp index 1185894e7..d84705c1a 100644 --- a/third_party/variant/optional.hpp +++ b/third_party/variant/include/mapbox/optional.hpp @@ -6,7 +6,7 @@ #include #include -#include "variant.hpp" +#include namespace mapbox { namespace util { @@ -22,7 +22,7 @@ class optional variant variant_; - public: +public: optional() = default; optional(optional const& rhs) diff --git a/third_party/variant/recursive_wrapper.hpp b/third_party/variant/include/mapbox/recursive_wrapper.hpp similarity index 96% rename from third_party/variant/recursive_wrapper.hpp rename to third_party/variant/include/mapbox/recursive_wrapper.hpp index 4becdd689..4ffcbd7c9 100644 --- a/third_party/variant/recursive_wrapper.hpp +++ b/third_party/variant/include/mapbox/recursive_wrapper.hpp @@ -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())) {} diff --git a/third_party/variant/variant.hpp b/third_party/variant/include/mapbox/variant.hpp similarity index 71% rename from third_party/variant/variant.hpp rename to third_party/variant/include/mapbox/variant.hpp index db5d3c86b..fb0f77e6d 100644 --- a/third_party/variant/variant.hpp +++ b/third_party/variant/include/mapbox/variant.hpp @@ -10,8 +10,10 @@ #include #include #include +#include -#include "recursive_wrapper.hpp" +#include +#include // 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 struct direct_type { static constexpr std::size_t index = std::is_same::value - ? sizeof...(Types) - : direct_type::index; + ? sizeof...(Types) + : direct_type::index; }; template @@ -98,6 +105,26 @@ struct direct_type static constexpr std::size_t index = invalid_value; }; +#if __cpp_lib_logical_traits >= 201510L + +using std::disjunction; + +#else + +template +struct disjunction : std::false_type {}; + +template +struct disjunction : B1 {}; + +template +struct disjunction : std::conditional::type {}; + +template +struct disjunction : std::conditional>::type {}; + +#endif + template struct convertible_type; @@ -105,8 +132,8 @@ template struct convertible_type { static constexpr std::size_t index = std::is_convertible::value - ? sizeof...(Types) - : convertible_type::index; + ? disjunction...>::value ? invalid_value : sizeof...(Types) + : convertible_type::index; }; template @@ -118,7 +145,7 @@ struct convertible_type template struct value_traits { - using value_type = typename std::remove_reference::type; + using value_type = typename std::remove_const::type>::type; static constexpr std::size_t direct_index = direct_type::index; static constexpr bool is_direct = direct_index != invalid_value; static constexpr std::size_t index = is_direct ? direct_index : convertible_type::index; @@ -127,35 +154,6 @@ struct value_traits using target_type = typename std::tuple_element>::type; }; -// check if T is in Types... -template -struct has_type; - -template -struct has_type -{ - static constexpr bool value = std::is_same::value || has_type::value; -}; - -template -struct has_type : std::false_type -{ -}; - -template -struct is_valid_type; - -template -struct is_valid_type -{ - static constexpr bool value = std::is_convertible::value || is_valid_type::value; -}; - -template -struct is_valid_type : std::false_type -{ -}; - template struct enable_if_type { @@ -299,7 +297,7 @@ struct dispatcher { if (v.template is()) { - return f(unwrapper::apply_const(v.template get())); + return f(unwrapper::apply_const(v.template get_unchecked())); } else { @@ -311,7 +309,7 @@ struct dispatcher { if (v.template is()) { - return f(unwrapper::apply(v.template get())); + return f(unwrapper::apply(v.template get_unchecked())); } else { @@ -325,12 +323,12 @@ struct dispatcher { VARIANT_INLINE static R apply_const(V const& v, F&& f) { - return f(unwrapper::apply_const(v.template get())); + return f(unwrapper::apply_const(v.template get_unchecked())); } VARIANT_INLINE static R apply(V& v, F&& f) { - return f(unwrapper::apply(v.template get())); + return f(unwrapper::apply(v.template get_unchecked())); } }; @@ -344,8 +342,8 @@ struct binary_dispatcher_rhs { if (rhs.template is()) // call binary functor { - return f(unwrapper::apply_const(lhs.template get()), - unwrapper::apply_const(rhs.template get())); + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); } else { @@ -357,8 +355,8 @@ struct binary_dispatcher_rhs { if (rhs.template is()) // call binary functor { - return f(unwrapper::apply(lhs.template get()), - unwrapper::apply(rhs.template get())); + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); } else { @@ -372,14 +370,14 @@ struct binary_dispatcher_rhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { - return f(unwrapper::apply_const(lhs.template get()), - unwrapper::apply_const(rhs.template get())); + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { - return f(unwrapper::apply(lhs.template get()), - unwrapper::apply(rhs.template get())); + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); } }; @@ -393,8 +391,8 @@ struct binary_dispatcher_lhs { if (lhs.template is()) // call binary functor { - return f(unwrapper::apply_const(lhs.template get()), - unwrapper::apply_const(rhs.template get())); + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); } else { @@ -406,8 +404,8 @@ struct binary_dispatcher_lhs { if (lhs.template is()) // call binary functor { - return f(unwrapper::apply(lhs.template get()), - unwrapper::apply(rhs.template get())); + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); } else { @@ -421,14 +419,14 @@ struct binary_dispatcher_lhs { VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) { - return f(unwrapper::apply_const(lhs.template get()), - unwrapper::apply_const(rhs.template get())); + return f(unwrapper::apply_const(lhs.template get_unchecked()), + unwrapper::apply_const(rhs.template get_unchecked())); } VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f) { - return f(unwrapper::apply(lhs.template get()), - unwrapper::apply(rhs.template get())); + return f(unwrapper::apply(lhs.template get_unchecked()), + unwrapper::apply(rhs.template get_unchecked())); } }; @@ -444,8 +442,8 @@ struct binary_dispatcher { if (v1.template is()) { - return f(unwrapper::apply_const(v0.template get()), - unwrapper::apply_const(v1.template get())); // call binary functor + return f(unwrapper::apply_const(v0.template get_unchecked()), + unwrapper::apply_const(v1.template get_unchecked())); // call binary functor } else { @@ -465,8 +463,8 @@ struct binary_dispatcher { if (v1.template is()) { - return f(unwrapper::apply(v0.template get()), - unwrapper::apply(v1.template get())); // call binary functor + return f(unwrapper::apply(v0.template get_unchecked()), + unwrapper::apply(v1.template get_unchecked())); // call binary functor } else { @@ -486,14 +484,14 @@ struct binary_dispatcher { VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) { - return f(unwrapper::apply_const(v0.template get()), - unwrapper::apply_const(v1.template get())); // call binary functor + return f(unwrapper::apply_const(v0.template get_unchecked()), + unwrapper::apply_const(v1.template get_unchecked())); // call binary functor } VARIANT_INLINE static R apply(V& v0, V& v1, F&& f) { - return f(unwrapper::apply(v0.template get()), - unwrapper::apply(v1.template get())); // call binary functor + return f(unwrapper::apply(v0.template get_unchecked()), + unwrapper::apply(v1.template get_unchecked())); // call binary functor } }; @@ -519,7 +517,7 @@ struct less_comp template class comparer { - public: +public: explicit comparer(Variant const& lhs) noexcept : lhs_(lhs) {} comparer& operator=(comparer const&) = delete; @@ -527,26 +525,22 @@ class comparer template bool operator()(T const& rhs_content) const { - T const& lhs_content = lhs_.template get(); + T const& lhs_content = lhs_.template get_unchecked(); return Comp()(lhs_content, rhs_content); } - private: +private: Variant const& lhs_; }; -// True if Predicate matches for all of the types Ts -template