Squashed 'third_party/variant/' content from commit 24dcab2
git-subtree-dir: third_party/variant git-subtree-split: 24dcab23c4f70e54838e4a32a228aba8045ae17b
This commit is contained in:
		
						commit
						884c998622
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
.DS_Store
 | 
			
		||||
out
 | 
			
		||||
profiling
 | 
			
		||||
							
								
								
									
										22
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
language: cpp
 | 
			
		||||
 | 
			
		||||
# http://docs.travis-ci.com/user/multi-os/
 | 
			
		||||
os:
 | 
			
		||||
  - linux
 | 
			
		||||
  - osx
 | 
			
		||||
 | 
			
		||||
compiler:
 | 
			
		||||
 - clang
 | 
			
		||||
 - gcc
 | 
			
		||||
 | 
			
		||||
before_install:
 | 
			
		||||
 - true
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
 - true
 | 
			
		||||
 | 
			
		||||
before_script:
 | 
			
		||||
 - true
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
 - source "scripts/${TRAVIS_OS_NAME}.sh"
 | 
			
		||||
							
								
								
									
										61
									
								
								Jamroot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Jamroot
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
local BOOST_DIR = "/opt/boost" ;
 | 
			
		||||
 | 
			
		||||
#using clang : : ;
 | 
			
		||||
 | 
			
		||||
lib system : : <name>boost_system <search>$(BOOST_DIR)/lib ;
 | 
			
		||||
lib timer : chrono : <name>boost_timer <search>$(BOOST_DIR)/lib ;
 | 
			
		||||
lib chrono : system : <name>boost_chrono <search>$(BOOST_DIR)/lib ;
 | 
			
		||||
 | 
			
		||||
exe variant-test
 | 
			
		||||
    :
 | 
			
		||||
    test/bench_variant.cpp
 | 
			
		||||
    .//system
 | 
			
		||||
    .//timer
 | 
			
		||||
    .//chrono
 | 
			
		||||
    :
 | 
			
		||||
    <include>$(BOOST_DIR)/include
 | 
			
		||||
    <include>./
 | 
			
		||||
    <cxxflags>-std=c++11
 | 
			
		||||
    #<define>SINGLE_THREADED
 | 
			
		||||
    <variant>release:<cxxflags>-march=native
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
exe binary-visitor-test
 | 
			
		||||
    :
 | 
			
		||||
    test/binary_visitor_test.cpp
 | 
			
		||||
    .//system
 | 
			
		||||
    .//timer
 | 
			
		||||
    .//chrono
 | 
			
		||||
    :
 | 
			
		||||
    <include>$(BOOST_DIR)/include
 | 
			
		||||
    <include>./
 | 
			
		||||
    <cxxflags>-std=c++11
 | 
			
		||||
    <variant>release:<cxxflags>-march=native
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
exe recursive-wrapper-test
 | 
			
		||||
    :
 | 
			
		||||
    test/recursive_wrapper_test.cpp
 | 
			
		||||
    .//system
 | 
			
		||||
    .//timer
 | 
			
		||||
    .//chrono
 | 
			
		||||
    :
 | 
			
		||||
    <include>$(BOOST_DIR)/include
 | 
			
		||||
    <include>./
 | 
			
		||||
    <cxxflags>-std=c++11
 | 
			
		||||
    <variant>release:<cxxflags>-march=native
 | 
			
		||||
    ;
 | 
			
		||||
 | 
			
		||||
exe unique-ptr-test
 | 
			
		||||
    :
 | 
			
		||||
    test/unique_ptr_test.cpp
 | 
			
		||||
    .//system
 | 
			
		||||
    .//timer
 | 
			
		||||
    .//chrono
 | 
			
		||||
    :
 | 
			
		||||
    <include>$(BOOST_DIR)/include
 | 
			
		||||
    <include>./
 | 
			
		||||
    <cxxflags>-std=c++11
 | 
			
		||||
    <variant>release:<cxxflags>-march=native
 | 
			
		||||
    ;
 | 
			
		||||
							
								
								
									
										25
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
Copyright (c) MapBox
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
- Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
- Redistributions in binary form must reproduce the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer in the documentation and/or
 | 
			
		||||
  other materials provided with the distribution.
 | 
			
		||||
- Neither the name "MapBox" nor the names of its contributors may be
 | 
			
		||||
  used to endorse or promote products derived from this software without
 | 
			
		||||
  specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 | 
			
		||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 | 
			
		||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										98
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
			
		||||
CXX := $(CXX)
 | 
			
		||||
BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
 | 
			
		||||
RELEASE_FLAGS = -O3 -DNDEBUG -finline-functions -march=native -DSINGLE_THREADED
 | 
			
		||||
DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
 | 
			
		||||
COMMON_FLAGS = -Wall -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -pedantic -fvisibility-inlines-hidden -std=c++11
 | 
			
		||||
CXXFLAGS := $(CXXFLAGS)
 | 
			
		||||
LDFLAGS := $(LDFLAGS)
 | 
			
		||||
 | 
			
		||||
OS:=$(shell uname -s)
 | 
			
		||||
ifeq ($(OS),Darwin)
 | 
			
		||||
	CXXFLAGS += -stdlib=libc++
 | 
			
		||||
	LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
 | 
			
		||||
else
 | 
			
		||||
    BOOST_LIBS += -lrt
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifeq (sizes,$(firstword $(MAKECMDGOALS)))
 | 
			
		||||
  RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
 | 
			
		||||
  $(eval $(RUN_ARGS):;@:)
 | 
			
		||||
  ifndef RUN_ARGS
 | 
			
		||||
  $(error sizes target requires you pass full path to boost variant.hpp)
 | 
			
		||||
  endif
 | 
			
		||||
  .PHONY: $(RUN_ARGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
 | 
			
		||||
 | 
			
		||||
./deps/gyp:
 | 
			
		||||
	git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
 | 
			
		||||
 | 
			
		||||
gyp: ./deps/gyp
 | 
			
		||||
	deps/gyp/gyp --depth=. -Goutput_dir=./ --generator-output=./out -f make
 | 
			
		||||
	make V=1 -C ./out tests
 | 
			
		||||
	./out/Release/tests
 | 
			
		||||
 | 
			
		||||
out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 | 
			
		||||
 | 
			
		||||
out/bench-variant: Makefile test/bench_variant.cpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 | 
			
		||||
 | 
			
		||||
out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 | 
			
		||||
 | 
			
		||||
out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 | 
			
		||||
 | 
			
		||||
out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
 | 
			
		||||
 | 
			
		||||
bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
 | 
			
		||||
	./out/bench-variant 100000
 | 
			
		||||
	./out/unique_ptr_test 100000
 | 
			
		||||
	./out/recursive_wrapper_test 100000
 | 
			
		||||
	./out/binary_visitor_test 100000
 | 
			
		||||
 | 
			
		||||
out/unit: Makefile test/unit.cpp test/optional_unit.cpp optional.hpp variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/unit test/unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
 | 
			
		||||
	$(CXX) -o out/optional_unit test/optional_unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
 | 
			
		||||
 | 
			
		||||
test: out/unit
 | 
			
		||||
	./out/unit
 | 
			
		||||
	./out/optional_unit
 | 
			
		||||
 | 
			
		||||
coverage:
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	$(CXX) -o out/cov-test --coverage test/unit.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
 | 
			
		||||
 | 
			
		||||
sizes: Makefile variant.hpp
 | 
			
		||||
	mkdir -p ./out
 | 
			
		||||
	@$(CXX) -o ./out/variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/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/variant_hello_world ./test/variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/variant_hello_world
 | 
			
		||||
	@$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) &&  du -h ./out/boost_variant_hello_world
 | 
			
		||||
 | 
			
		||||
profile: out/bench-variant-debug
 | 
			
		||||
	mkdir -p profiling/
 | 
			
		||||
	rm -rf profiling/*
 | 
			
		||||
	iprofiler -timeprofiler -d profiling/ ./out/bench-variant-debug 500000
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -rf ./out
 | 
			
		||||
	rm -rf *.dSYM
 | 
			
		||||
	rm -f unit.gc*
 | 
			
		||||
	rm -f *gcov
 | 
			
		||||
 | 
			
		||||
pgo: out Makefile variant.hpp
 | 
			
		||||
	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
 | 
			
		||||
	./test-variant 500000 >/dev/null 2>/dev/null
 | 
			
		||||
	$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
 | 
			
		||||
 | 
			
		||||
.PHONY: sizes test
 | 
			
		||||
							
								
								
									
										66
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
# Mapbox Variant
 | 
			
		||||
 | 
			
		||||
An alternative to `boost::variant` for C++11.
 | 
			
		||||
 | 
			
		||||
[](https://travis-ci.org/mapbox/variant)
 | 
			
		||||
[](https://ci.appveyor.com/project/Mapbox/variant)
 | 
			
		||||
 | 
			
		||||
# Why use Mapbox Variant?
 | 
			
		||||
 | 
			
		||||
Mapbox variant has the same speedy performance of `boost::variant` but is faster to compile, results in smaller binaries, and has no dependencies.
 | 
			
		||||
 | 
			
		||||
For example on OS X 10.9 with clang++ and libc++:
 | 
			
		||||
 | 
			
		||||
Test | Mapbox Variant | Boost Variant
 | 
			
		||||
---- | -------------- | -------------
 | 
			
		||||
Size of pre-compiled header (release / debug) | 2.8/2.8 MB         | 12/15 MB
 | 
			
		||||
Size of simple program linking variant (release / debug)     | 8/24 K             | 12/40 K
 | 
			
		||||
Time to compile header     | 185 ms             |  675 ms
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Depends
 | 
			
		||||
 | 
			
		||||
 - Compiler supporting `-std=c++11`
 | 
			
		||||
 | 
			
		||||
Tested with
 | 
			
		||||
 | 
			
		||||
 - g++-4.7
 | 
			
		||||
 - g++-4.8
 | 
			
		||||
 - clang++-3.4
 | 
			
		||||
 - clang++-3.5
 | 
			
		||||
 - Visual C++ Compiler November 2013 CTP
 | 
			
		||||
 - Visual C++ Compiler 2014 CTP 4
 | 
			
		||||
 | 
			
		||||
Note: get the "2013 Nov CTP" release at http://www.microsoft.com/en-us/download/details.aspx?id=41151 and the 2014 CTP at http://www.visualstudio.com/en-us/downloads/visual-studio-14-ctp-vs.aspx
 | 
			
		||||
 | 
			
		||||
# Usage
 | 
			
		||||
 | 
			
		||||
There is nothing to build, just include `variant.hpp` and `recursive_wrapper.hpp` in your project.
 | 
			
		||||
 | 
			
		||||
# Tests
 | 
			
		||||
 | 
			
		||||
The tests 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 test
 | 
			
		||||
 | 
			
		||||
On windows do:
 | 
			
		||||
 | 
			
		||||
    vcbuild
 | 
			
		||||
 | 
			
		||||
## Benchmark
 | 
			
		||||
 | 
			
		||||
On Unix systems run the benchmark like:
 | 
			
		||||
 | 
			
		||||
    make bench
 | 
			
		||||
 | 
			
		||||
## Check object sizes
 | 
			
		||||
 | 
			
		||||
    make sizes /path/to/boost/variant.hpp
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								appveyor.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
 | 
			
		||||
platform:
 | 
			
		||||
  - x64
 | 
			
		||||
  - x86
 | 
			
		||||
 | 
			
		||||
configuration:
 | 
			
		||||
  - Debug
 | 
			
		||||
  - Release
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  - SET PATH=c:\python27;%PATH%
 | 
			
		||||
  - SET PATH=C:\Program Files (x86)\MSBuild\12.0\bin\;%PATH%
 | 
			
		||||
  - git clone --quiet --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
 | 
			
		||||
  # note windows requires --generator-output to be absolute
 | 
			
		||||
  - python deps/gyp/gyp_main.py variant.gyp --depth=. -f msvs -G msvs_version=2013
 | 
			
		||||
  - set MSBUILD_PLATFORM=%platform%
 | 
			
		||||
  - if "%MSBUILD_PLATFORM%" == "x86" set MSBUILD_PLATFORM=Win32
 | 
			
		||||
  - msbuild variant.sln /nologo /p:Configuration=%configuration%;Platform=%MSBUILD_PLATFORM%
 | 
			
		||||
  - .\"%configuration%"\tests.exe
 | 
			
		||||
 | 
			
		||||
build: OFF
 | 
			
		||||
 | 
			
		||||
test: OFF
 | 
			
		||||
 | 
			
		||||
test_script: OFF
 | 
			
		||||
 | 
			
		||||
deploy: OFF
 | 
			
		||||
							
								
								
									
										143
									
								
								common.gypi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								common.gypi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,143 @@
 | 
			
		||||
{
 | 
			
		||||
  "conditions": [
 | 
			
		||||
    ["OS=='win'", {
 | 
			
		||||
          "target_defaults": {
 | 
			
		||||
            "default_configuration": "Release_x64",
 | 
			
		||||
            "msbuild_toolset":"CTP_Nov2013",
 | 
			
		||||
            "msvs_settings": {
 | 
			
		||||
              "VCCLCompilerTool": {
 | 
			
		||||
                "ExceptionHandling": 1, # /EHsc
 | 
			
		||||
                "RuntimeTypeInfo": "true" # /GR
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            "configurations": {
 | 
			
		||||
              "Debug_Win32": {
 | 
			
		||||
                "msvs_configuration_platform": "Win32",
 | 
			
		||||
                "defines": [ "DEBUG","_DEBUG"],
 | 
			
		||||
                "msvs_settings": {
 | 
			
		||||
                  "VCCLCompilerTool": {
 | 
			
		||||
                    "RuntimeLibrary": "1", # static debug /MTd
 | 
			
		||||
                    "Optimization": 0, # /Od, no optimization
 | 
			
		||||
                    "MinimalRebuild": "false",
 | 
			
		||||
                    "OmitFramePointers": "false",
 | 
			
		||||
                    "BasicRuntimeChecks": 3 # /RTC1
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              "Debug_x64": {
 | 
			
		||||
                "msvs_configuration_platform": "x64",
 | 
			
		||||
                "defines": [ "DEBUG","_DEBUG"],
 | 
			
		||||
                "msvs_settings": {
 | 
			
		||||
                  "VCCLCompilerTool": {
 | 
			
		||||
                    "RuntimeLibrary": "1", # static debug /MTd
 | 
			
		||||
                    "Optimization": 0, # /Od, no optimization
 | 
			
		||||
                    "MinimalRebuild": "false",
 | 
			
		||||
                    "OmitFramePointers": "false",
 | 
			
		||||
                    "BasicRuntimeChecks": 3 # /RTC1
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              "Release_Win32": {
 | 
			
		||||
                "msvs_configuration_platform": "Win32",
 | 
			
		||||
                "defines": [ "NDEBUG"],
 | 
			
		||||
                "msvs_settings": {
 | 
			
		||||
                  "VCCLCompilerTool": {
 | 
			
		||||
                    "RuntimeLibrary": 0, # static release
 | 
			
		||||
                    "Optimization": 3, # /Ox, full optimization
 | 
			
		||||
                    "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
 | 
			
		||||
                    "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
 | 
			
		||||
                    "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
 | 
			
		||||
                    "OmitFramePointers": "true",
 | 
			
		||||
                    "EnableFunctionLevelLinking": "true",
 | 
			
		||||
                    "EnableIntrinsicFunctions": "true",
 | 
			
		||||
                    "AdditionalOptions": [
 | 
			
		||||
                      "/MP", # compile across multiple CPUs
 | 
			
		||||
                    ],
 | 
			
		||||
                    "DebugInformationFormat": "0"
 | 
			
		||||
                  },
 | 
			
		||||
                  "VCLibrarianTool": {
 | 
			
		||||
                    "AdditionalOptions": [
 | 
			
		||||
                      "/LTCG" # link time code generation
 | 
			
		||||
                    ],
 | 
			
		||||
                  },
 | 
			
		||||
                  "VCLinkerTool": {
 | 
			
		||||
                    "LinkTimeCodeGeneration": 1, # link-time code generation
 | 
			
		||||
                    "OptimizeReferences": 2, # /OPT:REF
 | 
			
		||||
                    "EnableCOMDATFolding": 2, # /OPT:ICF
 | 
			
		||||
                    "LinkIncremental": 1, # disable incremental linking
 | 
			
		||||
                    "GenerateDebugInformation": "false"
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              "Release_x64": {
 | 
			
		||||
                "msvs_configuration_platform": "x64",
 | 
			
		||||
                "defines": [ "NDEBUG"],
 | 
			
		||||
                "msvs_settings": {
 | 
			
		||||
                  "VCCLCompilerTool": {
 | 
			
		||||
                    "RuntimeLibrary": 0, # static release
 | 
			
		||||
                    "Optimization": 3, # /Ox, full optimization
 | 
			
		||||
                    "FavorSizeOrSpeed": 1, # /Ot, favour speed over size
 | 
			
		||||
                    "InlineFunctionExpansion": 2, # /Ob2, inline anything eligible
 | 
			
		||||
                    "WholeProgramOptimization": "true", # /GL, whole program optimization, needed for LTCG
 | 
			
		||||
                    "OmitFramePointers": "true",
 | 
			
		||||
                    "EnableFunctionLevelLinking": "true",
 | 
			
		||||
                    "EnableIntrinsicFunctions": "true",
 | 
			
		||||
                    "AdditionalOptions": [
 | 
			
		||||
                      "/MP", # compile across multiple CPUs
 | 
			
		||||
                    ],
 | 
			
		||||
                    "DebugInformationFormat": "0"
 | 
			
		||||
                  },
 | 
			
		||||
                  "VCLibrarianTool": {
 | 
			
		||||
                    "AdditionalOptions": [
 | 
			
		||||
                      "/LTCG" # link time code generation
 | 
			
		||||
                    ],
 | 
			
		||||
                  },
 | 
			
		||||
                  "VCLinkerTool": {
 | 
			
		||||
                    "LinkTimeCodeGeneration": 1, # link-time code generation
 | 
			
		||||
                    "OptimizeReferences": 2, # /OPT:REF
 | 
			
		||||
                    "EnableCOMDATFolding": 2, # /OPT:ICF
 | 
			
		||||
                    "LinkIncremental": 1, # disable incremental linking
 | 
			
		||||
                    "GenerateDebugInformation": "false"
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
    }, {
 | 
			
		||||
        "target_defaults": {
 | 
			
		||||
            "default_configuration": "Release",
 | 
			
		||||
            "xcode_settings": {
 | 
			
		||||
              "CLANG_CXX_LIBRARY": "libc++",
 | 
			
		||||
              "CLANG_CXX_LANGUAGE_STANDARD":"c++11",
 | 
			
		||||
              "GCC_VERSION": "com.apple.compilers.llvm.clang.1_0",
 | 
			
		||||
            },
 | 
			
		||||
            "cflags_cc": ["-std=c++11"],
 | 
			
		||||
            "configurations": {
 | 
			
		||||
                "Debug": {
 | 
			
		||||
                    "defines": [
 | 
			
		||||
                        "DEBUG"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "xcode_settings": {
 | 
			
		||||
                        "GCC_OPTIMIZATION_LEVEL": "0",
 | 
			
		||||
                        "GCC_GENERATE_DEBUGGING_SYMBOLS": "YES",
 | 
			
		||||
                        "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-g", "-O0" ]
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                "Release": {
 | 
			
		||||
                    "defines": [
 | 
			
		||||
                        "NDEBUG"
 | 
			
		||||
                    ],
 | 
			
		||||
                    "xcode_settings": {
 | 
			
		||||
                        "GCC_OPTIMIZATION_LEVEL": "3",
 | 
			
		||||
                        "GCC_GENERATE_DEBUGGING_SYMBOLS": "NO",
 | 
			
		||||
                        "DEAD_CODE_STRIPPING": "YES",
 | 
			
		||||
                        "GCC_INLINES_ARE_PRIVATE_EXTERN": "YES",
 | 
			
		||||
                        "OTHER_CPLUSPLUSFLAGS": [ "-Wall", "-Wextra", "-pedantic", "-O3" ]
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }]
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										69
									
								
								optional.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								optional.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
 | 
			
		||||
#define MAPBOX_UTIL_OPTIONAL_HPP
 | 
			
		||||
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
 | 
			
		||||
namespace mapbox
 | 
			
		||||
{
 | 
			
		||||
namespace util
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename T> class optional
 | 
			
		||||
{
 | 
			
		||||
    static_assert(!std::is_reference<T>::value, "optional doesn't support references");
 | 
			
		||||
 | 
			
		||||
    struct none_type
 | 
			
		||||
    {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    variant<none_type, T> variant_;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    optional() = default;
 | 
			
		||||
 | 
			
		||||
    optional(optional const &rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (this != &rhs)
 | 
			
		||||
        { // protect against invalid self-assignment
 | 
			
		||||
            variant_ = rhs.variant_;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optional(T const &v) { variant_ = v; }
 | 
			
		||||
 | 
			
		||||
    explicit operator bool() const noexcept { return variant_.template is<T>(); }
 | 
			
		||||
 | 
			
		||||
    T const &get() const { return variant_.template get<T>(); }
 | 
			
		||||
    T &get() { return variant_.template get<T>(); }
 | 
			
		||||
 | 
			
		||||
    T const &operator*() const { return this->get(); }
 | 
			
		||||
    T operator*() { return this->get(); }
 | 
			
		||||
 | 
			
		||||
    optional &operator=(T const &v)
 | 
			
		||||
    {
 | 
			
		||||
        variant_ = v;
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    optional &operator=(optional const &rhs)
 | 
			
		||||
    {
 | 
			
		||||
        if (this != &rhs)
 | 
			
		||||
        {
 | 
			
		||||
            variant_ = rhs.variant_;
 | 
			
		||||
        }
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename... Args> void emplace(Args &&... args)
 | 
			
		||||
    {
 | 
			
		||||
        variant_ = T{std::forward<Args>(args)...};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() { variant_ = none_type{}; }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										127
									
								
								recursive_wrapper.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								recursive_wrapper.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,127 @@
 | 
			
		||||
#ifndef MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
#define MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace mapbox { namespace util {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class recursive_wrapper
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using type = T;
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    T* p_;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    ~recursive_wrapper();
 | 
			
		||||
    recursive_wrapper();
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper(recursive_wrapper const& operand);
 | 
			
		||||
    recursive_wrapper(T const& operand);
 | 
			
		||||
    recursive_wrapper(recursive_wrapper&& operand);
 | 
			
		||||
    recursive_wrapper(T&& operand);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    void assign(const T& rhs);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        assign( rhs.get() );
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline recursive_wrapper& operator=(T const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        assign( rhs );
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void swap(recursive_wrapper& operand) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        T* temp = operand.p_;
 | 
			
		||||
        operand.p_ = p_;
 | 
			
		||||
        p_ = temp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        swap(rhs);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    recursive_wrapper& operator=(T&& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        get() = std::move(rhs);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    T& get() { return *get_pointer(); }
 | 
			
		||||
    const T& get() const { return *get_pointer(); }
 | 
			
		||||
    T* get_pointer() { return p_; }
 | 
			
		||||
    const T* get_pointer() const { return p_; }
 | 
			
		||||
    operator T const&() const { return this->get(); }
 | 
			
		||||
    operator T&() { return this->get(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::~recursive_wrapper()
 | 
			
		||||
{
 | 
			
		||||
    delete p_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::recursive_wrapper()
 | 
			
		||||
    : p_(new T)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::recursive_wrapper(recursive_wrapper const& operand)
 | 
			
		||||
    : p_(new T( operand.get() ))
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::recursive_wrapper(T const& operand)
 | 
			
		||||
    : p_(new T(operand))
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::recursive_wrapper(recursive_wrapper&& operand)
 | 
			
		||||
    : p_(operand.p_)
 | 
			
		||||
{
 | 
			
		||||
    operand.p_ = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
recursive_wrapper<T>::recursive_wrapper(T&& operand)
 | 
			
		||||
    : p_(new T( std::move(operand) ))
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void recursive_wrapper<T>::assign(const T& rhs)
 | 
			
		||||
{
 | 
			
		||||
    this->get() = rhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
 | 
			
		||||
{
 | 
			
		||||
    lhs.swap(rhs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
#endif // MAPBOX_UTIL_VARIANT_RECURSIVE_WRAPPER_HPP
 | 
			
		||||
							
								
								
									
										59
									
								
								scripts/linux.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								scripts/linux.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e -u
 | 
			
		||||
set -o pipefail
 | 
			
		||||
 | 
			
		||||
# ppa for latest boost
 | 
			
		||||
sudo add-apt-repository -y ppa:boost-latest/ppa
 | 
			
		||||
# ppa for g++ 4.7 and 4.8
 | 
			
		||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
 | 
			
		||||
sudo apt-get update -y
 | 
			
		||||
 | 
			
		||||
# install boost headers and g++ upgrades
 | 
			
		||||
sudo apt-get -y -qq install boost1.55 gcc-4.8 g++-4.8 gcc-4.7 g++-4.7
 | 
			
		||||
 | 
			
		||||
if [[ "$CXX" == "clang++" ]]; then
 | 
			
		||||
    echo 'running tests against clang++'
 | 
			
		||||
    make test
 | 
			
		||||
    make bench
 | 
			
		||||
    make clean
 | 
			
		||||
else
 | 
			
		||||
    # run tests against g++ 4.7
 | 
			
		||||
    export CXX="g++-4.7"; export CC="gcc-4.7"
 | 
			
		||||
    echo 'running tests against g++ 4.7'
 | 
			
		||||
    make test
 | 
			
		||||
    make bench
 | 
			
		||||
    make clean
 | 
			
		||||
 | 
			
		||||
    # run tests against g++ 4.8
 | 
			
		||||
    export CXX="g++-4.8"; export CC="gcc-4.8"
 | 
			
		||||
    echo 'running tests against g++ 4.8'
 | 
			
		||||
    make test
 | 
			
		||||
    make bench
 | 
			
		||||
    make clean
 | 
			
		||||
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# compare object sizes against boost::variant
 | 
			
		||||
echo 'comparing object sizes to boost::variant'
 | 
			
		||||
make sizes /usr/include/boost/variant.hpp
 | 
			
		||||
make clean
 | 
			
		||||
 | 
			
		||||
# test building with gyp
 | 
			
		||||
echo 'testing build with gyp'
 | 
			
		||||
make gyp
 | 
			
		||||
 | 
			
		||||
# run coverage when using clang++
 | 
			
		||||
if [[ $CXX == "clang++" ]]; then
 | 
			
		||||
    make clean
 | 
			
		||||
    make coverage
 | 
			
		||||
    git status
 | 
			
		||||
    ./out/cov-test
 | 
			
		||||
    cp unit*gc* test/
 | 
			
		||||
    sudo pip install cpp-coveralls
 | 
			
		||||
    coveralls -i variant.hpp -i recursive_wrapper.hpp --gcov-options '\-lp'
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# set strictness back to normal
 | 
			
		||||
# to avoid tripping up travis
 | 
			
		||||
set +e +u
 | 
			
		||||
							
								
								
									
										20
									
								
								scripts/osx.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								scripts/osx.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
set -e -u
 | 
			
		||||
set -o pipefail
 | 
			
		||||
 | 
			
		||||
# install boost headers
 | 
			
		||||
brew unlink boost
 | 
			
		||||
brew install boost
 | 
			
		||||
 | 
			
		||||
# run tests
 | 
			
		||||
make test
 | 
			
		||||
make bench
 | 
			
		||||
make clean
 | 
			
		||||
 | 
			
		||||
# compare object sizes against boost::variant
 | 
			
		||||
make sizes `brew --prefix`/include/boost/variant.hpp
 | 
			
		||||
make clean
 | 
			
		||||
 | 
			
		||||
# test building with gyp
 | 
			
		||||
make gyp
 | 
			
		||||
							
								
								
									
										204
									
								
								test/bench_variant.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								test/bench_variant.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,204 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <boost/variant.hpp>
 | 
			
		||||
#include <boost/timer/timer.hpp>
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
 | 
			
		||||
#define TEXT "Testing various variant implementations with a longish string ........................................."
 | 
			
		||||
//#define BOOST_VARIANT_MINIMIZE_SIZE
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
namespace test {
 | 
			
		||||
 | 
			
		||||
template <typename V>
 | 
			
		||||
struct Holder
 | 
			
		||||
{
 | 
			
		||||
    typedef V value_type;
 | 
			
		||||
    std::vector<value_type> data;
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void append_move(T && obj)
 | 
			
		||||
    {
 | 
			
		||||
        data.emplace_back(std::forward<T>(obj));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void append(T const& obj)
 | 
			
		||||
    {
 | 
			
		||||
        data.push_back(obj);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace test
 | 
			
		||||
 | 
			
		||||
struct print : util::static_visitor<>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << val << ":" << typeid(T).name() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename V>
 | 
			
		||||
struct dummy : boost::static_visitor<>
 | 
			
		||||
{
 | 
			
		||||
    dummy(V & v)
 | 
			
		||||
        : v_(v) {}
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        v_ = val;
 | 
			
		||||
    }
 | 
			
		||||
    V & v_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename V>
 | 
			
		||||
struct dummy2 : util::static_visitor<>
 | 
			
		||||
{
 | 
			
		||||
    dummy2(V & v)
 | 
			
		||||
        : v_(v) {}
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        v_.template set<T>(val);
 | 
			
		||||
    }
 | 
			
		||||
    V & v_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void run_boost_test(std::size_t runs)
 | 
			
		||||
{
 | 
			
		||||
    test::Holder<boost::variant<int, double, std::string>> h;
 | 
			
		||||
    h.data.reserve(runs);
 | 
			
		||||
    for (std::size_t i=0; i< runs; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        h.append_move(std::string(TEXT));
 | 
			
		||||
        h.append_move(123);
 | 
			
		||||
        h.append_move(3.14159);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boost::variant<int, double, std::string> v;
 | 
			
		||||
    for (auto const& v2 : h.data)
 | 
			
		||||
    {
 | 
			
		||||
        dummy<boost::variant<int, double, std::string>> d(v);
 | 
			
		||||
        boost::apply_visitor(d, v2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void run_variant_test(std::size_t runs)
 | 
			
		||||
{
 | 
			
		||||
    test::Holder<util::variant<int, double, std::string>> h;
 | 
			
		||||
    h.data.reserve(runs);
 | 
			
		||||
    for (std::size_t i=0; i< runs; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        h.append_move(std::string(TEXT));
 | 
			
		||||
        h.append_move(123);
 | 
			
		||||
        h.append_move(3.14159);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    util::variant<int, double, std::string> v;
 | 
			
		||||
    for (auto const& v2 : h.data)
 | 
			
		||||
    {
 | 
			
		||||
        dummy2<util::variant<int, double, std::string>> d(v);
 | 
			
		||||
        util::apply_visitor (d, v2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main (int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    if (argc!=2)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Usage:" << argv[0] << " <num-runs>" << std::endl;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifndef SINGLE_THREADED
 | 
			
		||||
    const std::size_t THREADS = 4;
 | 
			
		||||
#endif
 | 
			
		||||
    const std::size_t NUM_RUNS = static_cast<std::size_t>(std::stol(argv[1]));
 | 
			
		||||
 | 
			
		||||
#ifdef SINGLE_THREADED
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "custom variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        run_variant_test(NUM_RUNS);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "boost variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        run_boost_test(NUM_RUNS);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "custom variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        run_variant_test(NUM_RUNS);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "boost variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        run_boost_test(NUM_RUNS);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    {
 | 
			
		||||
        typedef std::vector<std::unique_ptr<std::thread>> thread_group;
 | 
			
		||||
        typedef thread_group::value_type value_type;
 | 
			
		||||
        thread_group tg;
 | 
			
		||||
        std::cerr << "custom variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer timer;
 | 
			
		||||
        for (std::size_t i=0; i<THREADS; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
 | 
			
		||||
        }
 | 
			
		||||
        std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        typedef std::vector<std::unique_ptr<std::thread>> thread_group;
 | 
			
		||||
        typedef thread_group::value_type value_type;
 | 
			
		||||
        thread_group tg;
 | 
			
		||||
        std::cerr << "boost variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer timer;
 | 
			
		||||
        for (std::size_t i=0; i<THREADS; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
 | 
			
		||||
        }
 | 
			
		||||
        std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        typedef std::vector<std::unique_ptr<std::thread>> thread_group;
 | 
			
		||||
        typedef thread_group::value_type value_type;
 | 
			
		||||
        thread_group tg;
 | 
			
		||||
        std::cerr << "custom variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer timer;
 | 
			
		||||
        for (std::size_t i=0; i<THREADS; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            tg.emplace_back(new std::thread(run_variant_test, NUM_RUNS));
 | 
			
		||||
        }
 | 
			
		||||
        std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        typedef std::vector<std::unique_ptr<std::thread>> thread_group;
 | 
			
		||||
        typedef thread_group::value_type value_type;
 | 
			
		||||
        thread_group tg;
 | 
			
		||||
        std::cerr << "boost variant: ";
 | 
			
		||||
        boost::timer::auto_cpu_timer timer;
 | 
			
		||||
        for (std::size_t i=0; i<THREADS; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            tg.emplace_back(new std::thread(run_boost_test, NUM_RUNS));
 | 
			
		||||
        }
 | 
			
		||||
        std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								test/binary_visitor_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								test/binary_visitor_test.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <boost/variant.hpp>
 | 
			
		||||
#include <boost/timer/timer.hpp>
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
#include "variant_io.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
namespace test {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct string_to_number {};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct string_to_number<double>
 | 
			
		||||
{
 | 
			
		||||
    double operator() (std::string const& str) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::stod(str);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct string_to_number<std::int64_t>
 | 
			
		||||
{
 | 
			
		||||
    std::int64_t operator() (std::string const& str) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::stoll(str);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct string_to_number<std::uint64_t>
 | 
			
		||||
{
 | 
			
		||||
    std::uint64_t operator() (std::string const& str) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::stoull(str);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct string_to_number<bool>
 | 
			
		||||
{
 | 
			
		||||
    bool operator() (std::string const& str) const
 | 
			
		||||
    {
 | 
			
		||||
        bool result;
 | 
			
		||||
        std::istringstream(str) >> std::boolalpha >> result;
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct javascript_equal_visitor : util::static_visitor<bool>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool operator() (T lhs, T rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return lhs == rhs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
 | 
			
		||||
    bool operator() (T lhs, std::string const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return lhs == string_to_number<T>()(rhs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
 | 
			
		||||
    bool operator() (std::string const& lhs, T rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return string_to_number<T>()(lhs) == rhs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T0, typename T1>
 | 
			
		||||
    bool operator() (T0 lhs, T1 rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return lhs == static_cast<T0>(rhs);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct javascript_equal
 | 
			
		||||
{
 | 
			
		||||
    javascript_equal(T const& lhs)
 | 
			
		||||
        : lhs_(lhs) {}
 | 
			
		||||
 | 
			
		||||
    bool operator() (T const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
 | 
			
		||||
    }
 | 
			
		||||
    T const& lhs_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace test
 | 
			
		||||
 | 
			
		||||
int main (/*int argc, char** argv*/)
 | 
			
		||||
{
 | 
			
		||||
    typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
 | 
			
		||||
    variant_type v0(3.14159);
 | 
			
		||||
    variant_type v1(std::string("3.14159"));
 | 
			
		||||
    variant_type v2(std::uint64_t(1));
 | 
			
		||||
 | 
			
		||||
    std::cerr << v0 << " == " << v1 << " -> "
 | 
			
		||||
              << std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    std::vector<variant_type> vec;
 | 
			
		||||
 | 
			
		||||
    vec.emplace_back(std::string("1"));
 | 
			
		||||
    vec.push_back(variant_type(std::uint64_t(2)));
 | 
			
		||||
    vec.push_back(variant_type(std::uint64_t(3)));
 | 
			
		||||
    vec.push_back(std::string("3.14159"));
 | 
			
		||||
    vec.emplace_back(3.14159);
 | 
			
		||||
 | 
			
		||||
    //auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
 | 
			
		||||
    //        return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
 | 
			
		||||
    //    });
 | 
			
		||||
 | 
			
		||||
    auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
 | 
			
		||||
 | 
			
		||||
    if (itr != std::end(vec))
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "found " << *itr << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "can't find " << v2 << '\n';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								test/boost_variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								test/boost_variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#include <boost/variant.hpp>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
struct check : boost::static_visitor<>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        if (val != 0) throw std::runtime_error("invalid");
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    typedef boost::variant<bool, int, double> variant_type;
 | 
			
		||||
    variant_type v(0);
 | 
			
		||||
    boost::apply_visitor(check(), v);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8683
									
								
								test/catch.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8683
									
								
								test/catch.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										82
									
								
								test/optional_unit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								test/optional_unit.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
#define CATCH_CONFIG_RUNNER
 | 
			
		||||
#include "catch.hpp"
 | 
			
		||||
 | 
			
		||||
#include "optional.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
struct dummy {
 | 
			
		||||
    dummy(int _m_1, int _m_2) : m_1(_m_1), m_2(_m_2) {}
 | 
			
		||||
    int m_1;
 | 
			
		||||
    int m_2;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main (int argc, char* const argv[])
 | 
			
		||||
{
 | 
			
		||||
    int result = Catch::Session().run(argc, argv);
 | 
			
		||||
    if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "optional can be instantiated with a POD type", "[optiona]" ) {
 | 
			
		||||
    mapbox::util::optional<double> dbl_opt;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(!dbl_opt);
 | 
			
		||||
    dbl_opt = 3.1415;
 | 
			
		||||
    REQUIRE(dbl_opt);
 | 
			
		||||
 | 
			
		||||
    REQUIRE(dbl_opt.get() == 3.1415);
 | 
			
		||||
    REQUIRE(*dbl_opt == 3.1415);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "copy c'tor", "[optiona]" ) {
 | 
			
		||||
    mapbox::util::optional<double> dbl_opt;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(!dbl_opt);
 | 
			
		||||
    dbl_opt = 3.1415;
 | 
			
		||||
    REQUIRE(dbl_opt);
 | 
			
		||||
 | 
			
		||||
    mapbox::util::optional<double> other = dbl_opt;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(other.get() == 3.1415);
 | 
			
		||||
    REQUIRE(*other == 3.1415);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "const operator*, const get()", "[optiona]" ) {
 | 
			
		||||
    mapbox::util::optional<double> dbl_opt = 3.1415;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(dbl_opt);
 | 
			
		||||
 | 
			
		||||
    const double pi1 = dbl_opt.get();
 | 
			
		||||
    const double pi2 = *dbl_opt;
 | 
			
		||||
 | 
			
		||||
    REQUIRE(pi1 == 3.1415);
 | 
			
		||||
    REQUIRE(pi2 == 3.1415);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "emplace initialization, reset", "[optional]" ) {
 | 
			
		||||
    mapbox::util::optional<dummy> dummy_opt;
 | 
			
		||||
    REQUIRE(!dummy_opt);
 | 
			
		||||
 | 
			
		||||
    // rvalues, baby!
 | 
			
		||||
    dummy_opt.emplace(1, 2);
 | 
			
		||||
    REQUIRE(dummy_opt);
 | 
			
		||||
    REQUIRE(dummy_opt.get().m_1 == 1);
 | 
			
		||||
    REQUIRE((*dummy_opt).m_2 == 2);
 | 
			
		||||
 | 
			
		||||
    dummy_opt.reset();
 | 
			
		||||
    REQUIRE(!dummy_opt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "assignment", "[optional]") {
 | 
			
		||||
    mapbox::util::optional<int> a;
 | 
			
		||||
    mapbox::util::optional<int> b;
 | 
			
		||||
 | 
			
		||||
    a = 1; b = 3;
 | 
			
		||||
    REQUIRE(a.get() == 1);
 | 
			
		||||
    REQUIRE(b.get() == 3);
 | 
			
		||||
    b = a;
 | 
			
		||||
    REQUIRE(a.get() == b.get());
 | 
			
		||||
    REQUIRE(b.get() == 1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								test/recursive_wrapper_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								test/recursive_wrapper_test.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <boost/timer/timer.hpp>
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
namespace test {
 | 
			
		||||
 | 
			
		||||
struct add;
 | 
			
		||||
struct sub;
 | 
			
		||||
template <typename OpTag> struct binary_op;
 | 
			
		||||
 | 
			
		||||
typedef util::variant<int ,
 | 
			
		||||
                      util::recursive_wrapper<binary_op<add>>,
 | 
			
		||||
                      util::recursive_wrapper<binary_op<sub>>
 | 
			
		||||
                      > expression;
 | 
			
		||||
 | 
			
		||||
template <typename Op>
 | 
			
		||||
struct binary_op
 | 
			
		||||
{
 | 
			
		||||
    expression left;  // variant instantiated here...
 | 
			
		||||
    expression right;
 | 
			
		||||
 | 
			
		||||
    binary_op(expression && lhs, expression && rhs)
 | 
			
		||||
        : left(std::move(lhs)), right(std::move(rhs))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct print : util::static_visitor<void>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << val << ":" << typeid(T).name() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct test : util::static_visitor<std::string>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    std::string operator() (T const& obj) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::string("TYPE_ID=") + typeid(obj).name();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct calculator : public util::static_visitor<int>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    int operator()(int value) const
 | 
			
		||||
    {
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int operator()(binary_op<add> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(calculator(), binary.left)
 | 
			
		||||
            + util::apply_visitor(calculator(), binary.right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int operator()(binary_op<sub> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(calculator(), binary.left)
 | 
			
		||||
            - util::apply_visitor(calculator(), binary.right);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct to_string : public util::static_visitor<std::string>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    std::string operator()(int value) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::to_string(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string operator()(binary_op<add> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(to_string(), binary.left) + std::string("+")
 | 
			
		||||
            + util::apply_visitor(to_string(), binary.right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string operator()(binary_op<sub> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(to_string(), binary.left) + std::string("-")
 | 
			
		||||
            + util::apply_visitor(to_string(), binary.right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace test
 | 
			
		||||
 | 
			
		||||
int main (int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    if (argc != 2)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
 | 
			
		||||
        return EXIT_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
 | 
			
		||||
 | 
			
		||||
    test::expression result(
 | 
			
		||||
        test::binary_op<test::sub>(
 | 
			
		||||
            test::binary_op<test::add>(2, 3), 4));
 | 
			
		||||
 | 
			
		||||
    std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (std::size_t i = 0; i < NUM_ITER; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            total += util::apply_visitor(test::calculator(), result);
 | 
			
		||||
        }
 | 
			
		||||
        std::cerr << "total=" << total << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
 | 
			
		||||
 | 
			
		||||
    return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								test/unique_ptr_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								test/unique_ptr_test.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,128 @@
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <boost/variant.hpp>
 | 
			
		||||
#include <boost/timer/timer.hpp>
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
namespace test {
 | 
			
		||||
 | 
			
		||||
struct add;
 | 
			
		||||
struct sub;
 | 
			
		||||
template <typename OpTag> struct binary_op;
 | 
			
		||||
 | 
			
		||||
typedef util::variant<int ,
 | 
			
		||||
                      std::unique_ptr<binary_op<add>>,
 | 
			
		||||
                      std::unique_ptr<binary_op<sub>>
 | 
			
		||||
                      > expression;
 | 
			
		||||
 | 
			
		||||
template <typename Op>
 | 
			
		||||
struct binary_op
 | 
			
		||||
{
 | 
			
		||||
    expression left;  // variant instantiated here...
 | 
			
		||||
    expression right;
 | 
			
		||||
 | 
			
		||||
    binary_op(expression && lhs, expression && rhs)
 | 
			
		||||
        : left(std::move(lhs)), right(std::move(rhs)) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct print : util::static_visitor<void>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << val << ":" << typeid(T).name() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct test : util::static_visitor<std::string>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    std::string operator() (T const& obj) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::string("TYPE_ID=") + typeid(obj).name();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct calculator : public util::static_visitor<int>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    int operator()(int value) const
 | 
			
		||||
    {
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int operator()(std::unique_ptr<binary_op<add>> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(calculator(), binary->left)
 | 
			
		||||
            + util::apply_visitor(calculator(), binary->right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int operator()(std::unique_ptr<binary_op<sub>> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(calculator(), binary->left)
 | 
			
		||||
            - util::apply_visitor(calculator(), binary->right);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct to_string : public util::static_visitor<std::string>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    std::string operator()(int value) const
 | 
			
		||||
    {
 | 
			
		||||
        return std::to_string(value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string operator()(std::unique_ptr<binary_op<add>> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(to_string(), binary->left) + std::string("+")
 | 
			
		||||
            + util::apply_visitor(to_string(), binary->right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string operator()(std::unique_ptr<binary_op<sub>> const& binary) const
 | 
			
		||||
    {
 | 
			
		||||
        return util::apply_visitor(to_string(), binary->left) + std::string("-")
 | 
			
		||||
            + util::apply_visitor(to_string(), binary->right);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace test
 | 
			
		||||
 | 
			
		||||
int main (int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
    if (argc != 2)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Usage" << argv[0] << " <num-iter>" << std::endl;
 | 
			
		||||
        return EXIT_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::size_t NUM_ITER = static_cast<std::size_t>(std::stol(argv[1]));
 | 
			
		||||
 | 
			
		||||
    test::expression sum(std::unique_ptr<test::binary_op<test::add>>(new test::binary_op<test::add>(2, 3)));
 | 
			
		||||
    test::expression result(std::unique_ptr<test::binary_op<test::sub>>(new test::binary_op<test::sub>(std::move(sum), 4)));
 | 
			
		||||
    std::cerr << "TYPE OF RESULT-> " << util::apply_visitor(test::test(), result) << std::endl;
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        boost::timer::auto_cpu_timer t;
 | 
			
		||||
        int total = 0;
 | 
			
		||||
        for (std::size_t i = 0; i < NUM_ITER; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            total += util::apply_visitor(test::calculator(), result);
 | 
			
		||||
        }
 | 
			
		||||
        std::cerr << "total=" << total << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::cerr << util::apply_visitor(test::to_string(), result) << "=" << util::apply_visitor(test::calculator(), result) << std::endl;
 | 
			
		||||
 | 
			
		||||
    return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										306
									
								
								test/unit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								test/unit.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,306 @@
 | 
			
		||||
#define CATCH_CONFIG_RUNNER
 | 
			
		||||
#include "catch.hpp"
 | 
			
		||||
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
#include "variant_io.hpp"
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <iterator>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct mutating_visitor
 | 
			
		||||
{
 | 
			
		||||
    mutating_visitor(T & val)
 | 
			
		||||
        : val_(val) {}
 | 
			
		||||
 | 
			
		||||
    void operator() (T & val) const
 | 
			
		||||
    {
 | 
			
		||||
        val = val_;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T1>
 | 
			
		||||
    void operator() (T1& ) const {} // no-op
 | 
			
		||||
 | 
			
		||||
    T & val_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant version", "[variant]" ) {
 | 
			
		||||
    unsigned int version = VARIANT_VERSION;
 | 
			
		||||
    REQUIRE(version == 100);
 | 
			
		||||
    #if VARIANT_VERSION == 100
 | 
			
		||||
        REQUIRE(true);
 | 
			
		||||
    #else
 | 
			
		||||
        REQUIRE(false);
 | 
			
		||||
    #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant can be moved into vector", "[variant]" ) {
 | 
			
		||||
    typedef util::variant<bool,std::string> variant_type;
 | 
			
		||||
    variant_type v(std::string("test"));
 | 
			
		||||
    std::vector<variant_type> vec;
 | 
			
		||||
    vec.emplace_back(std::move(v));
 | 
			
		||||
    REQUIRE(v.get<std::string>() != std::string("test"));
 | 
			
		||||
    REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant should support built-in types", "[variant]" ) {
 | 
			
		||||
    SECTION( "bool" ) {
 | 
			
		||||
        util::variant<bool> v(true);
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<bool>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<bool>() == true);
 | 
			
		||||
        v.set<bool>(false);
 | 
			
		||||
        REQUIRE(v.get<bool>() == false);
 | 
			
		||||
        v = true;
 | 
			
		||||
        REQUIRE(v == util::variant<bool>(true));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "nullptr" ) {
 | 
			
		||||
        typedef std::nullptr_t value_type;
 | 
			
		||||
        util::variant<value_type> v(nullptr);
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        // TODO: commented since it breaks on windows: 'operator << is ambiguous'
 | 
			
		||||
        //REQUIRE(v.get<value_type>() == nullptr);
 | 
			
		||||
        // FIXME: does not compile: ./variant.hpp:340:14: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::__1::basic_ostream<char>' and 'const nullptr_t')
 | 
			
		||||
        // https://github.com/mapbox/variant/issues/14
 | 
			
		||||
        //REQUIRE(v == util::variant<value_type>(nullptr));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "unique_ptr" ) {
 | 
			
		||||
        typedef std::unique_ptr<std::string> value_type;
 | 
			
		||||
        util::variant<value_type> v(value_type(new std::string("hello")));
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "string" ) {
 | 
			
		||||
        typedef std::string value_type;
 | 
			
		||||
        util::variant<value_type> v(value_type("hello"));
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type("hello"));
 | 
			
		||||
        v.set<value_type>(value_type("there"));
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type("there"));
 | 
			
		||||
        v = value_type("variant");
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type("variant")));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "size_t" ) {
 | 
			
		||||
        typedef std::size_t value_type;
 | 
			
		||||
        util::variant<value_type> v(std::numeric_limits<value_type>::max());
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
 | 
			
		||||
        v.set<value_type>(value_type(0));
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type(0));
 | 
			
		||||
        v = value_type(1);
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type(1)));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "int8_t" ) {
 | 
			
		||||
        typedef std::int8_t value_type;
 | 
			
		||||
        util::variant<value_type> v(std::numeric_limits<value_type>::max());
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
 | 
			
		||||
        v.set<value_type>(0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type(0));
 | 
			
		||||
        v = value_type(1);
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type(1)));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "int16_t" ) {
 | 
			
		||||
        typedef std::int16_t value_type;
 | 
			
		||||
        util::variant<value_type> v(std::numeric_limits<value_type>::max());
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
 | 
			
		||||
        v.set<value_type>(0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type(0));
 | 
			
		||||
        v = value_type(1);
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type(1)));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "int32_t" ) {
 | 
			
		||||
        typedef std::int32_t value_type;
 | 
			
		||||
        util::variant<value_type> v(std::numeric_limits<value_type>::max());
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
 | 
			
		||||
        v.set<value_type>(0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type(0));
 | 
			
		||||
        v = value_type(1);
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type(1)));
 | 
			
		||||
    }
 | 
			
		||||
    SECTION( "int64_t" ) {
 | 
			
		||||
        typedef std::int64_t value_type;
 | 
			
		||||
        util::variant<value_type> v(std::numeric_limits<value_type>::max());
 | 
			
		||||
        REQUIRE(v.valid());
 | 
			
		||||
        REQUIRE(v.is<value_type>());
 | 
			
		||||
        REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
 | 
			
		||||
        v.set<value_type>(0);
 | 
			
		||||
        REQUIRE(v.get<value_type>() == value_type(0));
 | 
			
		||||
        v = value_type(1);
 | 
			
		||||
        REQUIRE(v == util::variant<value_type>(value_type(1)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct MissionInteger
 | 
			
		||||
{
 | 
			
		||||
    typedef uint64_t value_type;
 | 
			
		||||
    value_type val_;
 | 
			
		||||
    public:
 | 
			
		||||
      MissionInteger(uint64_t val) :
 | 
			
		||||
       val_(val) {}
 | 
			
		||||
 | 
			
		||||
    bool operator==(MissionInteger const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return (val_ == rhs.get());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint64_t get() const
 | 
			
		||||
    {
 | 
			
		||||
        return val_;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO - remove after https://github.com/mapbox/variant/issues/14
 | 
			
		||||
std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
 | 
			
		||||
{
 | 
			
		||||
    os << rhs.get();
 | 
			
		||||
    return os;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant should support custom types", "[variant]" ) {
 | 
			
		||||
    // http://www.missionintegers.com/integer/34838300
 | 
			
		||||
    util::variant<MissionInteger> v(MissionInteger(34838300));
 | 
			
		||||
    REQUIRE(v.valid());
 | 
			
		||||
    REQUIRE(v.is<MissionInteger>());
 | 
			
		||||
    REQUIRE(v.get_type_index() == 0);
 | 
			
		||||
    REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
 | 
			
		||||
    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
 | 
			
		||||
    // TODO: should both of the set usages below compile?
 | 
			
		||||
    v.set<MissionInteger>(MissionInteger::value_type(0));
 | 
			
		||||
    v.set<MissionInteger>(MissionInteger(0));
 | 
			
		||||
    REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
 | 
			
		||||
    v = MissionInteger(1);
 | 
			
		||||
    REQUIRE(v == util::variant<MissionInteger>(MissionInteger(1)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test internal api
 | 
			
		||||
TEST_CASE( "variant should correctly index types", "[variant]" ) {
 | 
			
		||||
    typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
 | 
			
		||||
    // Index is in reverse order
 | 
			
		||||
    REQUIRE(variant_type(true).get_type_index() == 5);
 | 
			
		||||
    REQUIRE(variant_type(std::string("test")).get_type_index() == 4);
 | 
			
		||||
    REQUIRE(variant_type(std::uint64_t(0)).get_type_index() == 3);
 | 
			
		||||
    REQUIRE(variant_type(std::int64_t(0)).get_type_index() == 2);
 | 
			
		||||
    REQUIRE(variant_type(double(0.0)).get_type_index() == 1);
 | 
			
		||||
    REQUIRE(variant_type(float(0.0)).get_type_index() == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "get with type not in variant type list should throw", "[variant]" ) {
 | 
			
		||||
    typedef util::variant<int> variant_type;
 | 
			
		||||
    variant_type var = 5;
 | 
			
		||||
    REQUIRE(var.get<int>() == 5);
 | 
			
		||||
    REQUIRE_THROWS(var.get<double>()); // XXX shouldn't this be a compile time error? See https://github.com/mapbox/variant/issues/24
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "get with wrong type (here: double) should throw", "[variant]" ) {
 | 
			
		||||
    typedef util::variant<int, double> variant_type;
 | 
			
		||||
    variant_type var = 5;
 | 
			
		||||
    REQUIRE(var.get<int>() == 5);
 | 
			
		||||
    REQUIRE_THROWS(var.get<double>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "get with wrong type (here: int) should throw", "[variant]" ) {
 | 
			
		||||
    typedef util::variant<int, double> variant_type;
 | 
			
		||||
    variant_type var = 5.0;
 | 
			
		||||
    REQUIRE(var.get<double>() == 5.0);
 | 
			
		||||
    REQUIRE_THROWS(var.get<int>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "implicit conversion", "[variant][implicit conversion]" ) {
 | 
			
		||||
    typedef util::variant<int> variant_type;
 | 
			
		||||
    variant_type var(5.0); // converted to int
 | 
			
		||||
    REQUIRE(var.get<int>() == 5);
 | 
			
		||||
    REQUIRE_THROWS(var.get<double>());
 | 
			
		||||
    var = 6.0; // works for operator=, too
 | 
			
		||||
    REQUIRE(var.get<int>() == 6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "implicit conversion to first type in variant type list", "[variant][implicit conversion]" ) {
 | 
			
		||||
    typedef util::variant<long, char> variant_type;
 | 
			
		||||
    variant_type var = 5.0; // converted to long
 | 
			
		||||
    REQUIRE(var.get<long>() == 5);
 | 
			
		||||
    REQUIRE_THROWS(var.get<char>());
 | 
			
		||||
    REQUIRE_THROWS(var.get<double>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "implicit conversion to unsigned char", "[variant][implicit conversion]" ) {
 | 
			
		||||
    typedef util::variant<unsigned char> variant_type;
 | 
			
		||||
    variant_type var = 100.0;
 | 
			
		||||
    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(100.0));
 | 
			
		||||
    CHECK(var.get<unsigned char>() == static_cast<unsigned char>(static_cast<unsigned int>(100.0)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct dummy {};
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant value traits", "[variant::detail]" ) {
 | 
			
		||||
    // Users should not create variants with duplicated types
 | 
			
		||||
    // however our type indexing should still work
 | 
			
		||||
    // Index is in reverse order
 | 
			
		||||
    REQUIRE((util::detail::value_traits<bool, bool, int, double, std::string>::index == 3));
 | 
			
		||||
    REQUIRE((util::detail::value_traits<int, bool, int, double, std::string>::index == 2));
 | 
			
		||||
    REQUIRE((util::detail::value_traits<double, bool, int, double, std::string>::index == 1));
 | 
			
		||||
    REQUIRE((util::detail::value_traits<std::string, bool, int, double, std::string>::index == 0));
 | 
			
		||||
    REQUIRE((util::detail::value_traits<dummy, bool, int, double, std::string>::index == util::detail::invalid_value));
 | 
			
		||||
    REQUIRE((util::detail::value_traits<std::vector<int>, bool, int, double, std::string>::index == util::detail::invalid_value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant default constructor", "[variant][default constructor]" ) {
 | 
			
		||||
    // By default variant is initialised with (default constructed) first type in template parameters pack
 | 
			
		||||
    // As a result first type in Types... must be default constructable
 | 
			
		||||
    // NOTE: index in reverse order -> index = N - 1
 | 
			
		||||
    REQUIRE((util::variant<int, double, std::string>().get_type_index() == 2));
 | 
			
		||||
    REQUIRE((util::variant<int, double, std::string>(util::no_init()).get_type_index() == util::detail::invalid_value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant visitation", "[visitor][unary visitor]" ) {
 | 
			
		||||
    util::variant<int, double, std::string> var(123);
 | 
			
		||||
    REQUIRE(var.get<int>() == 123);
 | 
			
		||||
    int val = 456;
 | 
			
		||||
    mutating_visitor<int> visitor(val);
 | 
			
		||||
    util::apply_visitor(visitor, var);
 | 
			
		||||
    REQUIRE(var.get<int>() == 456);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_CASE( "variant printer", "[visitor][unary visitor][printer]" ) {
 | 
			
		||||
    typedef util::variant<int, double, std::string> variant_type;
 | 
			
		||||
    std::vector<variant_type> var = {2.1, 123, "foo", 456};
 | 
			
		||||
    std::stringstream out;
 | 
			
		||||
    std::copy(var.begin(), var.end(), std::ostream_iterator<variant_type>(out, ","));
 | 
			
		||||
    out << var[2];
 | 
			
		||||
    REQUIRE(out.str() == "2.1,123,foo,456,foo");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main (int argc, char* const argv[])
 | 
			
		||||
{
 | 
			
		||||
    int result = Catch::Session().run(argc, argv);
 | 
			
		||||
    if (!result) printf("\x1b[1;32m ✓ \x1b[0m\n");
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								test/variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								test/variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
#include "variant.hpp"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
using namespace mapbox;
 | 
			
		||||
 | 
			
		||||
struct check : util::static_visitor<>
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator() (T const& val) const
 | 
			
		||||
    {
 | 
			
		||||
        if (val != 0) throw std::runtime_error("invalid");
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    typedef util::variant<bool, int, double> variant_type;
 | 
			
		||||
    variant_type v(0);
 | 
			
		||||
    util::apply_visitor(check(), v);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								variant.gyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								variant.gyp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
{
 | 
			
		||||
  "includes": [
 | 
			
		||||
      "common.gypi"
 | 
			
		||||
  ],
 | 
			
		||||
  "targets": [
 | 
			
		||||
    {
 | 
			
		||||
      "target_name": "tests",
 | 
			
		||||
      "type": "executable",
 | 
			
		||||
      "sources": [
 | 
			
		||||
        "test/unit.cpp"
 | 
			
		||||
      ],
 | 
			
		||||
      "xcode_settings": {
 | 
			
		||||
        "SDKROOT": "macosx",
 | 
			
		||||
        "SUPPORTED_PLATFORMS":["macosx"]
 | 
			
		||||
      },
 | 
			
		||||
      "include_dirs": [
 | 
			
		||||
          "./"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										755
									
								
								variant.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										755
									
								
								variant.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,755 @@
 | 
			
		||||
#ifndef MAPBOX_UTIL_VARIANT_HPP
 | 
			
		||||
#define MAPBOX_UTIL_VARIANT_HPP
 | 
			
		||||
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <typeinfo>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <stdexcept> // runtime_error
 | 
			
		||||
#include <new> // operator new
 | 
			
		||||
#include <cstddef> // size_t
 | 
			
		||||
#include <iosfwd>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "recursive_wrapper.hpp"
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
 // http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
 | 
			
		||||
 #ifdef NDEBUG
 | 
			
		||||
  #define VARIANT_INLINE __forceinline
 | 
			
		||||
 #else
 | 
			
		||||
  #define VARIANT_INLINE __declspec(noinline)
 | 
			
		||||
 #endif
 | 
			
		||||
#else
 | 
			
		||||
 #ifdef NDEBUG
 | 
			
		||||
  #define VARIANT_INLINE inline __attribute__((always_inline))
 | 
			
		||||
 #else
 | 
			
		||||
  #define VARIANT_INLINE __attribute__((noinline))
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define VARIANT_MAJOR_VERSION 0
 | 
			
		||||
#define VARIANT_MINOR_VERSION 1
 | 
			
		||||
#define VARIANT_PATCH_VERSION 0
 | 
			
		||||
 | 
			
		||||
// translates to 100
 | 
			
		||||
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
 | 
			
		||||
 | 
			
		||||
namespace mapbox { namespace util {
 | 
			
		||||
 | 
			
		||||
// static visitor
 | 
			
		||||
template <typename R = void>
 | 
			
		||||
struct static_visitor
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
protected:
 | 
			
		||||
    static_visitor() {}
 | 
			
		||||
    ~static_visitor() {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
static constexpr std::size_t invalid_value = std::size_t(-1);
 | 
			
		||||
 | 
			
		||||
template <typename T, typename...Types>
 | 
			
		||||
struct direct_type;
 | 
			
		||||
 | 
			
		||||
template <typename T, typename First, typename...Types>
 | 
			
		||||
struct direct_type<T, First, Types...>
 | 
			
		||||
{
 | 
			
		||||
    static constexpr std::size_t index = std::is_same<T, First>::value
 | 
			
		||||
        ? sizeof...(Types) : direct_type<T, Types...>::index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct direct_type<T>
 | 
			
		||||
{
 | 
			
		||||
    static constexpr std::size_t index = invalid_value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename...Types>
 | 
			
		||||
struct convertible_type;
 | 
			
		||||
 | 
			
		||||
template <typename T, typename First, typename...Types>
 | 
			
		||||
struct convertible_type<T, First, Types...>
 | 
			
		||||
{
 | 
			
		||||
    static constexpr std::size_t index = std::is_convertible<T, First>::value
 | 
			
		||||
        ? sizeof...(Types) : convertible_type<T, Types...>::index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct convertible_type<T>
 | 
			
		||||
{
 | 
			
		||||
    static constexpr std::size_t index = invalid_value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename...Types>
 | 
			
		||||
struct value_traits
 | 
			
		||||
{
 | 
			
		||||
    static constexpr std::size_t direct_index = direct_type<T, Types...>::index;
 | 
			
		||||
    static constexpr std::size_t index =
 | 
			
		||||
        (direct_index == invalid_value) ? convertible_type<T, Types...>::index : direct_index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 <std::size_t N, typename ... Types>
 | 
			
		||||
struct select_type
 | 
			
		||||
{
 | 
			
		||||
    static_assert(N < sizeof...(Types), "index out of bounds");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <std::size_t N, typename T, typename ... Types>
 | 
			
		||||
struct select_type<N, T, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using type = typename select_type<N - 1, Types...>::type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T, typename ... Types>
 | 
			
		||||
struct select_type<0, T, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using type = T;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T, typename R = void>
 | 
			
		||||
struct enable_if_type { using type = R; };
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename Enable = void>
 | 
			
		||||
struct result_of_unary_visit
 | 
			
		||||
{
 | 
			
		||||
    using type = typename std::result_of<F(V&)>::type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V>
 | 
			
		||||
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
 | 
			
		||||
{
 | 
			
		||||
    using type = typename F::result_type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, class Enable = void>
 | 
			
		||||
struct result_of_binary_visit
 | 
			
		||||
{
 | 
			
		||||
    using type = typename std::result_of<F(V&,V&)>::type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V>
 | 
			
		||||
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
 | 
			
		||||
{
 | 
			
		||||
    using type = typename F::result_type;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace detail
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <std::size_t arg1, std::size_t ... others>
 | 
			
		||||
struct static_max;
 | 
			
		||||
 | 
			
		||||
template <std::size_t arg>
 | 
			
		||||
struct static_max<arg>
 | 
			
		||||
{
 | 
			
		||||
    static const std::size_t value = arg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <std::size_t arg1, std::size_t arg2, std::size_t ... others>
 | 
			
		||||
struct static_max<arg1, arg2, others...>
 | 
			
		||||
{
 | 
			
		||||
    static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value :
 | 
			
		||||
        static_max<arg2, others...>::value;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename... Types>
 | 
			
		||||
struct variant_helper;
 | 
			
		||||
 | 
			
		||||
template<typename T, typename... Types>
 | 
			
		||||
struct variant_helper<T, Types...>
 | 
			
		||||
{
 | 
			
		||||
    VARIANT_INLINE static void destroy(const std::size_t id, void * data)
 | 
			
		||||
    {
 | 
			
		||||
        if (id == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            reinterpret_cast<T*>(data)->~T();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            variant_helper<Types...>::destroy(id, data);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static void move(const std::size_t old_id, void * old_value, void * new_value)
 | 
			
		||||
    {
 | 
			
		||||
        if (old_id == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
 | 
			
		||||
            //std::memcpy(new_value, old_value, sizeof(T));
 | 
			
		||||
            // ^^  DANGER: this should only be considered for relocatable types e.g built-in types
 | 
			
		||||
            // Also, I don't see any measurable performance benefit just yet
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            variant_helper<Types...>::move(old_id, old_value, new_value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static void copy(const std::size_t old_id, const void * old_value, void * new_value)
 | 
			
		||||
    {
 | 
			
		||||
        if (old_id == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            new (new_value) T(*reinterpret_cast<const T*>(old_value));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            variant_helper<Types...>::copy(old_id, old_value, new_value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<> struct variant_helper<>
 | 
			
		||||
{
 | 
			
		||||
    VARIANT_INLINE static void destroy(const std::size_t, void *) {}
 | 
			
		||||
    VARIANT_INLINE static void move(const std::size_t, void *, void *) {}
 | 
			
		||||
    VARIANT_INLINE static void copy(const std::size_t, const void *, void *) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct unwrapper
 | 
			
		||||
{
 | 
			
		||||
    T const& operator() (T const& obj) const
 | 
			
		||||
    {
 | 
			
		||||
        return obj;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T& operator() (T & obj) const
 | 
			
		||||
    {
 | 
			
		||||
        return obj;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct unwrapper<recursive_wrapper<T>>
 | 
			
		||||
{
 | 
			
		||||
    auto operator() (recursive_wrapper<T> const& obj) const
 | 
			
		||||
        -> typename recursive_wrapper<T>::type const&
 | 
			
		||||
    {
 | 
			
		||||
        return obj.get();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename...Types>
 | 
			
		||||
struct dispatcher;
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename T, typename...Types>
 | 
			
		||||
struct dispatcher<F, V, R, T, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const& v, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (v.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            return f(unwrapper<T>()(v. template get<T>()));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return dispatcher<F, V, R, Types...>::apply_const(v, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V & v, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (v.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            return f(unwrapper<T>()(v. template get<T>()));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return dispatcher<F, V, R, Types...>::apply(v, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename F, typename V, typename R>
 | 
			
		||||
struct dispatcher<F, V, R>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const&, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V &, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename T, typename...Types>
 | 
			
		||||
struct binary_dispatcher_rhs;
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
 | 
			
		||||
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
 | 
			
		||||
        {
 | 
			
		||||
            return f(unwrapper<T0>()(lhs. template get<T0>()),
 | 
			
		||||
                     unwrapper<T1>()(rhs. template get<T1>()));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
 | 
			
		||||
        {
 | 
			
		||||
            return f(unwrapper<T0>()(lhs. template get<T0>()),
 | 
			
		||||
                     unwrapper<T1>()(rhs. template get<T1>()));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename F, typename V, typename R, typename T>
 | 
			
		||||
struct binary_dispatcher_rhs<F, V, R, T>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V &, V &, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R,  typename T, typename...Types>
 | 
			
		||||
struct binary_dispatcher_lhs;
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
 | 
			
		||||
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
 | 
			
		||||
        {
 | 
			
		||||
            return f(lhs. template get<T1>(), rhs. template get<T0>());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
 | 
			
		||||
        {
 | 
			
		||||
            return f(lhs. template get<T1>(), rhs. template get<T0>());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename F, typename V, typename R, typename T>
 | 
			
		||||
struct binary_dispatcher_lhs<F, V, R, T>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V &, V &, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename...Types>
 | 
			
		||||
struct binary_dispatcher;
 | 
			
		||||
 | 
			
		||||
template <typename F, typename V, typename R, typename T, typename...Types>
 | 
			
		||||
struct binary_dispatcher<F, V, R, T, Types...>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (v0.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            if (v0.get_type_index() == v1.get_type_index())
 | 
			
		||||
            {
 | 
			
		||||
                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (v1.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
 | 
			
		||||
        }
 | 
			
		||||
        return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
 | 
			
		||||
    {
 | 
			
		||||
        if (v0.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            if (v0.get_type_index() == v1.get_type_index())
 | 
			
		||||
            {
 | 
			
		||||
                return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (v1.get_type_index() == sizeof...(Types))
 | 
			
		||||
        {
 | 
			
		||||
            return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, f);
 | 
			
		||||
        }
 | 
			
		||||
        return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename F, typename V, typename R>
 | 
			
		||||
struct binary_dispatcher<F, V, R>
 | 
			
		||||
{
 | 
			
		||||
    using result_type = R;
 | 
			
		||||
    VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE static result_type apply(V &, V &, F)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error("binary dispatch: FAIL");
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// comparator functors
 | 
			
		||||
struct equal_comp
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool operator()(T const& lhs, T const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return lhs == rhs;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct less_comp
 | 
			
		||||
{
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    bool operator()(T const& lhs, T const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        return lhs < rhs;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Variant, typename Comp>
 | 
			
		||||
class comparer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit comparer(Variant const& lhs) noexcept
 | 
			
		||||
        : lhs_(lhs) {}
 | 
			
		||||
    comparer& operator=(comparer const&) = delete;
 | 
			
		||||
    // visitor
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    bool operator()(T const& rhs_content) const
 | 
			
		||||
    {
 | 
			
		||||
        T const& lhs_content = lhs_.template get<T>();
 | 
			
		||||
        return Comp()(lhs_content, rhs_content);
 | 
			
		||||
    }
 | 
			
		||||
private:
 | 
			
		||||
    Variant const& lhs_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
} // namespace detail
 | 
			
		||||
 | 
			
		||||
struct no_init {};
 | 
			
		||||
 | 
			
		||||
template<typename... Types>
 | 
			
		||||
class variant
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    static const std::size_t data_size = static_max<sizeof(Types)...>::value;
 | 
			
		||||
    static const std::size_t data_align = static_max<alignof(Types)...>::value;
 | 
			
		||||
 | 
			
		||||
    using data_type = typename std::aligned_storage<data_size, data_align>::type;
 | 
			
		||||
    using helper_type = variant_helper<Types...>;
 | 
			
		||||
 | 
			
		||||
    std::size_t type_index;
 | 
			
		||||
    data_type data;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE variant()
 | 
			
		||||
        : type_index(sizeof...(Types) - 1)
 | 
			
		||||
    {
 | 
			
		||||
        new (&data) typename detail::select_type<0, Types...>::type();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE variant(no_init)
 | 
			
		||||
        : type_index(detail::invalid_value) {}
 | 
			
		||||
 | 
			
		||||
    // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
 | 
			
		||||
    template <typename T, class = typename std::enable_if<
 | 
			
		||||
                          detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type>
 | 
			
		||||
    VARIANT_INLINE variant(T && val) noexcept
 | 
			
		||||
        : type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index)
 | 
			
		||||
    {
 | 
			
		||||
        constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1;
 | 
			
		||||
        using target_type = typename detail::select_type<index, Types...>::type;
 | 
			
		||||
        new (&data) target_type(std::forward<T>(val)); // nothrow
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE variant(variant<Types...> const& old)
 | 
			
		||||
        : type_index(old.type_index)
 | 
			
		||||
    {
 | 
			
		||||
        helper_type::copy(old.type_index, &old.data, &data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE variant(variant<Types...>&& old) noexcept
 | 
			
		||||
        : type_index(old.type_index)
 | 
			
		||||
    {
 | 
			
		||||
        helper_type::move(old.type_index, &old.data, &data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    friend void swap(variant<Types...> & first, variant<Types...> & second)
 | 
			
		||||
    {
 | 
			
		||||
        using std::swap; //enable ADL
 | 
			
		||||
        swap(first.type_index, second.type_index);
 | 
			
		||||
        swap(first.data, second.data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE variant<Types...>& operator=(variant<Types...> other)
 | 
			
		||||
    {
 | 
			
		||||
        swap(*this, other);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // conversions
 | 
			
		||||
    // move-assign
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        variant<Types...> temp(std::forward<T>(rhs));
 | 
			
		||||
        swap(*this, temp);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // copy-assign
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
 | 
			
		||||
    {
 | 
			
		||||
        variant<Types...> temp(rhs);
 | 
			
		||||
        swap(*this, temp);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    VARIANT_INLINE bool is() const
 | 
			
		||||
    {
 | 
			
		||||
        return (type_index == detail::direct_type<T, Types...>::index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE bool valid() const
 | 
			
		||||
    {
 | 
			
		||||
        return (type_index != detail::invalid_value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T, typename... Args>
 | 
			
		||||
    VARIANT_INLINE void set(Args&&... args)
 | 
			
		||||
    {
 | 
			
		||||
        helper_type::destroy(type_index, &data);
 | 
			
		||||
        new (&data) T(std::forward<Args>(args)...);
 | 
			
		||||
        type_index = detail::direct_type<T, Types...>::index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    VARIANT_INLINE T& get()
 | 
			
		||||
    {
 | 
			
		||||
        if (type_index == detail::direct_type<T, Types...>::index)
 | 
			
		||||
        {
 | 
			
		||||
            return *reinterpret_cast<T*>(&data);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("in get()");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename T>
 | 
			
		||||
    VARIANT_INLINE T const& get() const
 | 
			
		||||
    {
 | 
			
		||||
        if (type_index == detail::direct_type<T, Types...>::index)
 | 
			
		||||
        {
 | 
			
		||||
            return *reinterpret_cast<T const*>(&data);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("in get()");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VARIANT_INLINE std::size_t get_type_index() const
 | 
			
		||||
    {
 | 
			
		||||
        return type_index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // visitor
 | 
			
		||||
    // unary
 | 
			
		||||
    template <typename F, typename V>
 | 
			
		||||
    auto VARIANT_INLINE
 | 
			
		||||
    static visit(V const& v, F f)
 | 
			
		||||
        -> decltype(detail::dispatcher<F, V,
 | 
			
		||||
                    typename detail::result_of_unary_visit<F,
 | 
			
		||||
                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v, f))
 | 
			
		||||
    {
 | 
			
		||||
        using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
 | 
			
		||||
        return detail::dispatcher<F, V, R, Types...>::apply_const(v, f);
 | 
			
		||||
    }
 | 
			
		||||
    // non-const
 | 
			
		||||
    template <typename F, typename V>
 | 
			
		||||
    auto VARIANT_INLINE
 | 
			
		||||
    static visit(V & v, F f)
 | 
			
		||||
        -> decltype(detail::dispatcher<F, V,
 | 
			
		||||
                    typename detail::result_of_unary_visit<F,
 | 
			
		||||
                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v, f))
 | 
			
		||||
    {
 | 
			
		||||
        using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
 | 
			
		||||
        return detail::dispatcher<F, V, R, Types...>::apply(v, f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // binary
 | 
			
		||||
    // const
 | 
			
		||||
    template <typename F, typename V>
 | 
			
		||||
    auto VARIANT_INLINE
 | 
			
		||||
    static binary_visit(V const& v0, V const& v1, F f)
 | 
			
		||||
        -> decltype(detail::binary_dispatcher<F, V,
 | 
			
		||||
                    typename detail::result_of_binary_visit<F,
 | 
			
		||||
                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v0, v1, f))
 | 
			
		||||
    {
 | 
			
		||||
        using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
 | 
			
		||||
        return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
 | 
			
		||||
    }
 | 
			
		||||
    // non-const
 | 
			
		||||
    template <typename F, typename V>
 | 
			
		||||
    auto VARIANT_INLINE
 | 
			
		||||
    static binary_visit(V& v0, V& v1, F f)
 | 
			
		||||
        -> decltype(detail::binary_dispatcher<F, V,
 | 
			
		||||
                    typename detail::result_of_binary_visit<F,
 | 
			
		||||
                    typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v0, v1, f))
 | 
			
		||||
    {
 | 
			
		||||
        using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
 | 
			
		||||
        return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~variant() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        helper_type::destroy(type_index, &data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // comparison operators
 | 
			
		||||
    // equality
 | 
			
		||||
    VARIANT_INLINE bool operator==(variant const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->get_type_index() != rhs.get_type_index())
 | 
			
		||||
            return false;
 | 
			
		||||
        detail::comparer<variant, detail::equal_comp> visitor(*this);
 | 
			
		||||
        return visit(rhs, visitor);
 | 
			
		||||
    }
 | 
			
		||||
    // less than
 | 
			
		||||
    VARIANT_INLINE bool operator<(variant const& rhs) const
 | 
			
		||||
    {
 | 
			
		||||
        if (this->get_type_index() != rhs.get_type_index())
 | 
			
		||||
        {
 | 
			
		||||
            return this->get_type_index() < rhs.get_type_index();
 | 
			
		||||
            // ^^ borrowed from boost::variant
 | 
			
		||||
        }
 | 
			
		||||
        detail::comparer<variant, detail::less_comp> visitor(*this);
 | 
			
		||||
        return visit(rhs, visitor);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// unary visitor interface
 | 
			
		||||
 | 
			
		||||
// const
 | 
			
		||||
template <typename V, typename F>
 | 
			
		||||
auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
 | 
			
		||||
{
 | 
			
		||||
    return V::visit(v, f);
 | 
			
		||||
}
 | 
			
		||||
// non-const
 | 
			
		||||
template <typename V, typename F>
 | 
			
		||||
auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
 | 
			
		||||
{
 | 
			
		||||
    return V::visit(v, f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// binary visitor interface
 | 
			
		||||
// const
 | 
			
		||||
template <typename V, typename F>
 | 
			
		||||
auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
 | 
			
		||||
{
 | 
			
		||||
    return V::binary_visit(v0, v1, f);
 | 
			
		||||
}
 | 
			
		||||
// non-const
 | 
			
		||||
template <typename V, typename F>
 | 
			
		||||
auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
 | 
			
		||||
{
 | 
			
		||||
    return V::binary_visit(v0, v1, f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getter interface
 | 
			
		||||
template<typename ResultType, typename T>
 | 
			
		||||
ResultType &  get(T & var)
 | 
			
		||||
{
 | 
			
		||||
    return var.template get<ResultType>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename ResultType, typename T>
 | 
			
		||||
ResultType const&  get(T const& var)
 | 
			
		||||
{
 | 
			
		||||
    return var.template get<ResultType>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
#endif  // MAPBOX_UTIL_VARIANT_HPP
 | 
			
		||||
							
								
								
									
										39
									
								
								variant_io.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								variant_io.hpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
#define MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
 | 
			
		||||
namespace mapbox { namespace util {
 | 
			
		||||
 | 
			
		||||
namespace detail {
 | 
			
		||||
// operator<< helper
 | 
			
		||||
template <typename Out>
 | 
			
		||||
class printer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit printer(Out & out)
 | 
			
		||||
        : out_(out) {}
 | 
			
		||||
    printer& operator=(printer const&) = delete;
 | 
			
		||||
 | 
			
		||||
// visitor
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void operator()(T const& operand) const
 | 
			
		||||
    {
 | 
			
		||||
        out_ << operand;
 | 
			
		||||
    }
 | 
			
		||||
private:
 | 
			
		||||
    Out & out_;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// operator<<
 | 
			
		||||
template <typename charT, typename traits, typename... Types>
 | 
			
		||||
VARIANT_INLINE std::basic_ostream<charT, traits>&
 | 
			
		||||
operator<< (std::basic_ostream<charT, traits>& out, variant<Types...> const& rhs)
 | 
			
		||||
{
 | 
			
		||||
    detail::printer<std::basic_ostream<charT, traits>> visitor(out);
 | 
			
		||||
    apply_visitor(visitor, rhs);
 | 
			
		||||
    return out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}}
 | 
			
		||||
 | 
			
		||||
#endif //MAPBOX_UTIL_VARIANT_IO_HPP
 | 
			
		||||
							
								
								
									
										8
									
								
								vcbuild.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vcbuild.bat
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
SET configuration=Debug
 | 
			
		||||
IF NOT EXIST deps\gyp\ git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
 | 
			
		||||
IF EXIST %configuration% rd /s /q %configuration%
 | 
			
		||||
del variant.sln
 | 
			
		||||
del tests.vcxproj
 | 
			
		||||
C:\Python27\python.exe deps/gyp/gyp_main.py variant.gyp --depth=. -f msvs -G msvs_version=2013
 | 
			
		||||
msbuild variant.sln /nologo /p:Configuration=%configuration%;Platform=Win32
 | 
			
		||||
.\"%configuration%"\tests.exe
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user