Merge commit 'b65f1d7df0b997eac085da7f5a3344a86b812916' as 'Include/variant'
This commit is contained in:
		
						commit
						0077856d2f
					
				
							
								
								
									
										3
									
								
								Include/variant/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Include/variant/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| .DS_Store | ||||
| out | ||||
| profiling | ||||
							
								
								
									
										22
									
								
								Include/variant/.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Include/variant/.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
									
								
								Include/variant/Jamroot
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Include/variant/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
									
								
								Include/variant/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Include/variant/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. | ||||
							
								
								
									
										92
									
								
								Include/variant/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Include/variant/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,92 @@ | ||||
| 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 | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| 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
									
								
								Include/variant/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Include/variant/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
									
								
								Include/variant/appveyor.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Include/variant/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
									
								
								Include/variant/common.gypi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								Include/variant/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
									
								
								Include/variant/optional.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								Include/variant/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
									
								
								Include/variant/recursive_wrapper.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								Include/variant/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
 | ||||
							
								
								
									
										40
									
								
								Include/variant/scripts/linux.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Include/variant/scripts/linux.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| #!/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 | ||||
| 
 | ||||
| # 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 | ||||
| 
 | ||||
| # 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 | ||||
| 
 | ||||
| # set strictness back to normal | ||||
| # to avoid tripping up travis | ||||
| set +e +u | ||||
							
								
								
									
										20
									
								
								Include/variant/scripts/osx.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Include/variant/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
									
								
								Include/variant/test/bench_variant.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								Include/variant/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; | ||||
| } | ||||
							
								
								
									
										135
									
								
								Include/variant/test/binary_visitor_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								Include/variant/test/binary_visitor_test.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| #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" | ||||
| 
 | ||||
| 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
									
								
								Include/variant/test/boost_variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Include/variant/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
									
								
								Include/variant/test/catch.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8683
									
								
								Include/variant/test/catch.hpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										82
									
								
								Include/variant/test/optional_unit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								Include/variant/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
									
								
								Include/variant/test/recursive_wrapper_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								Include/variant/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
									
								
								Include/variant/test/unique_ptr_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								Include/variant/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
									
								
								Include/variant/test/unit.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										306
									
								
								Include/variant/test/unit.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,306 @@ | ||||
| #define CATCH_CONFIG_RUNNER | ||||
| #include "catch.hpp" | ||||
| 
 | ||||
| #include "variant.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
									
								
								Include/variant/test/variant_hello_world.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Include/variant/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
									
								
								Include/variant/variant.gyp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Include/variant/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": [ | ||||
|           "./" | ||||
|       ] | ||||
|     } | ||||
|   ] | ||||
| } | ||||
							
								
								
									
										783
									
								
								Include/variant/variant.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										783
									
								
								Include/variant/variant.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,783 @@ | ||||
| #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_; | ||||
| }; | ||||
| 
 | ||||
| // 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_; | ||||
| }; | ||||
| 
 | ||||
| } // 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>(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // 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_HPP
 | ||||
							
								
								
									
										8
									
								
								Include/variant/vcbuild.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Include/variant/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