Remove variant

This commit is contained in:
Patrick Niklaus 2016-03-24 21:30:38 +01:00
parent 17babb22e2
commit be2cc7aed9
28 changed files with 0 additions and 11493 deletions

View File

@ -1,5 +0,0 @@
.DS_Store
out
profiling
build
deps

View File

@ -1,22 +0,0 @@
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"

View File

@ -1,75 +0,0 @@
local BOOST_DIR = "/usr/local" ;
#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
;
exe reference_wrapper_test
:
test/reference_wrapper_test.cpp
.//system
.//timer
.//chrono
:
<include>$(BOOST_DIR)/include
<include>./
<cxxflags>-std=c++11
<variant>release:<cxxflags>-march=native
;

View File

@ -1,25 +0,0 @@
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.

View File

@ -1,100 +0,0 @@
CXX := $(CXX)
BOOST_LIBS = -lboost_timer -lboost_system -lboost_chrono
RELEASE_FLAGS = -O3 -DNDEBUG -finline-functions -march=native -DSINGLE_THREADED
DEBUG_FLAGS = -O0 -g -DDEBUG -fno-inline-functions
COMMON_FLAGS = -Wall -Wsign-compare -Wsign-conversion -Wshadow -Wunused-parameter -pedantic -fvisibility-inlines-hidden -std=c++11
CXXFLAGS := $(CXXFLAGS)
LDFLAGS := $(LDFLAGS)
OS:=$(shell uname -s)
ifeq ($(OS),Darwin)
CXXFLAGS += -stdlib=libc++
LDFLAGS += -stdlib=libc++ -F/ -framework CoreFoundation
else
BOOST_LIBS += -lrt
endif
ifeq (sizes,$(firstword $(MAKECMDGOALS)))
RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
$(eval $(RUN_ARGS):;@:)
ifndef RUN_ARGS
$(error sizes target requires you pass full path to boost variant.hpp)
endif
.PHONY: $(RUN_ARGS)
endif
all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
./deps/gyp:
git clone --depth 1 https://chromium.googlesource.com/external/gyp.git ./deps/gyp
gyp: ./deps/gyp
deps/gyp/gyp --depth=. -Goutput_dir=./ --generator-output=./out -f make
make V=1 -C ./out tests
./out/Release/tests
out/bench-variant-debug: Makefile test/bench_variant.cpp variant.hpp
mkdir -p ./out
$(CXX) -o out/bench-variant-debug test/bench_variant.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
out/bench-variant: Makefile test/bench_variant.cpp variant.hpp
mkdir -p ./out
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
out/unique_ptr_test: Makefile test/unique_ptr_test.cpp variant.hpp
mkdir -p ./out
$(CXX) -o out/unique_ptr_test test/unique_ptr_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
out/recursive_wrapper_test: Makefile test/recursive_wrapper_test.cpp variant.hpp
mkdir -p ./out
$(CXX) -o out/recursive_wrapper_test test/recursive_wrapper_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
out/binary_visitor_test: Makefile test/binary_visitor_test.cpp variant.hpp
mkdir -p ./out
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS)
bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
./out/bench-variant 100000
./out/unique_ptr_test 100000
./out/recursive_wrapper_test 100000
./out/binary_visitor_test 100000
out/unit: Makefile test/unit.cpp test/optional_unit.cpp optional.hpp variant.hpp
mkdir -p ./out
$(CXX) -o out/unit test/unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
$(CXX) -o out/optional_unit test/optional_unit.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
test: out/unit
./out/unit
./out/optional_unit
coverage:
mkdir -p ./out
$(CXX) -o out/cov-test --coverage test/unit.cpp -I./ $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS)
sizes: Makefile variant.hpp
mkdir -p ./out
@$(CXX) -o ./out/variant_hello_world.out variant.hpp $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/variant_hello_world.out
@$(CXX) -o ./out/boost_variant_hello_world.out $(RUN_ARGS) $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world.out
@$(CXX) -o ./out/variant_hello_world ./test/variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/variant_hello_world
@$(CXX) -o ./out/boost_variant_hello_world ./test/boost_variant_hello_world.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) && du -h ./out/boost_variant_hello_world
profile: out/bench-variant-debug
mkdir -p profiling/
rm -rf profiling/*
iprofiler -timeprofiler -d profiling/ ./out/bench-variant-debug 500000
clean:
rm -rf ./out
rm -rf *.dSYM
rm -f unit.gc*
rm -f *gcov
rm -f test/unit.gc*
rm -f test/*gcov
pgo: out Makefile variant.hpp
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -pg -fprofile-generate
./test-variant 500000 >/dev/null 2>/dev/null
$(CXX) -o out/bench-variant test/bench_variant.cpp -I./ $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_LIBS) -fprofile-use
.PHONY: sizes test

View File

@ -1,67 +0,0 @@
# Mapbox Variant
An alternative to `boost::variant` for C++11.
[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master)](https://coveralls.io/r/mapbox/variant?branch=master)
# 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

View File

@ -1,17 +0,0 @@
platform:
- x64
- x86
configuration:
- Debug
- Release
os: Visual Studio 2015
install:
- CALL scripts\build-appveyor.bat
build: off
test: off
deploy: off

View File

@ -1,143 +0,0 @@
{
"conditions": [
["OS=='win'", {
"target_defaults": {
"default_configuration": "Release_x64",
"msbuild_toolset":"v140",
"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" ]
}
}
}
}
}]
]
}

View File

@ -1,69 +0,0 @@
#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

View File

@ -1,127 +0,0 @@
#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

View File

@ -1,32 +0,0 @@
@ECHO OFF
SETLOCAL
SET PATH=c:\python27;%PATH%
ECHO activating VS command prompt
IF /I "%PLATFORM"=="x64" (
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
) ELSE (
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
)
IF NOT EXIST deps\gyp git clone --depth 1 https://chromium.googlesource.com/external/gyp.git deps/gyp
CALL deps\gyp\gyp.bat variant.gyp --depth=. ^
-f msvs ^
-G msvs_version=2015 ^
--generator-output=build
SET MSBUILD_PLATFORM=%platform%
IF /I "%MSBUILD_PLATFORM%" == "x86" SET MSBUILD_PLATFORM=Win32
msbuild ^
build\variant.sln ^
/nologo ^
/toolsversion:14.0 ^
/p:PlatformToolset=v140 ^
/p:Configuration=%configuration% ^
/p:Platform=%MSBUILD_PLATFORM%
build\"%configuration%"\tests.exe

View File

@ -1,7 +0,0 @@
@ECHO OFF
SETLOCAL
SET platform=x64
SET configuration=Release
CALL scripts\build-appveyor.bat

View File

@ -1,59 +0,0 @@
#!/usr/bin/env bash
set -e -u
set -o pipefail
# ppa for latest boost
sudo add-apt-repository -y ppa:boost-latest/ppa
# ppa for g++ 4.7 and 4.8
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
sudo apt-get update -y
# install boost headers and g++ upgrades
sudo apt-get -y -qq install boost1.55 gcc-4.8 g++-4.8 gcc-4.7 g++-4.7
if [[ "$CXX" == "clang++" ]]; then
echo 'running tests against clang++'
make test
make bench
make clean
else
# run tests against g++ 4.7
export CXX="g++-4.7"; export CC="gcc-4.7"
echo 'running tests against g++ 4.7'
make test
make bench
make clean
# run tests against g++ 4.8
export CXX="g++-4.8"; export CC="gcc-4.8"
echo 'running tests against g++ 4.8'
make test
make bench
make clean
fi
# compare object sizes against boost::variant
echo 'comparing object sizes to boost::variant'
make sizes /usr/include/boost/variant.hpp
make clean
# test building with gyp
echo 'testing build with gyp'
make gyp
# run coverage when using clang++
if [[ $CXX == "clang++" ]]; then
make clean
make coverage
git status
./out/cov-test
cp unit*gc* test/
sudo pip install cpp-coveralls
coveralls -i variant.hpp -i recursive_wrapper.hpp --gcov-options '\-lp'
fi
# set strictness back to normal
# to avoid tripping up travis
set +e +u

View File

@ -1,20 +0,0 @@
#!/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

View File

@ -1,181 +0,0 @@
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <utility>
#include <boost/variant.hpp>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
#define TEXT_SHORT "Test"
#define TEXT_LONG "Testing various variant implementations with a longish string ........................................."
#define NUM_SAMPLES 3
//#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 && val) const
{
v_ = std::move(val);
}
V & v_;
};
template <typename V>
struct dummy2 : util::static_visitor<>
{
dummy2(V & v)
: v_(v) {}
template <typename T>
void operator() (T && val) const
{
v_ = std::move(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_SHORT));
h.append_move(std::string(TEXT_LONG));
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_SHORT));
h.append_move(std::string(TEXT_LONG));
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
for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
{
{
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
for (std::size_t j = 0; j < NUM_SAMPLES; ++j)
{
{
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;
}

View File

@ -1,136 +0,0 @@
#include <cstdint>
#include <iostream>
#include <vector>
#include <thread>
#include <string>
#include <sstream>
#include <utility>
#include <type_traits>
#include <boost/variant.hpp>
#include <boost/timer/timer.hpp>
#include "variant.hpp"
#include "variant_io.hpp"
using namespace mapbox;
namespace test {
template <typename T>
struct string_to_number {};
template <>
struct string_to_number<double>
{
double operator() (std::string const& str) const
{
return std::stod(str);
}
};
template <>
struct string_to_number<std::int64_t>
{
std::int64_t operator() (std::string const& str) const
{
return std::stoll(str);
}
};
template <>
struct string_to_number<std::uint64_t>
{
std::uint64_t operator() (std::string const& str) const
{
return std::stoull(str);
}
};
template <>
struct string_to_number<bool>
{
bool operator() (std::string const& str) const
{
bool result;
std::istringstream(str) >> std::boolalpha >> result;
return result;
}
};
struct javascript_equal_visitor : util::static_visitor<bool>
{
template <typename T>
bool operator() (T lhs, T rhs) const
{
return lhs == rhs;
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator() (T lhs, std::string const& rhs) const
{
return lhs == string_to_number<T>()(rhs);
}
template <typename T, class = typename std::enable_if<std::is_arithmetic<T>::value>::type>
bool operator() (std::string const& lhs, T rhs) const
{
return string_to_number<T>()(lhs) == rhs;
}
template <typename T0, typename T1>
bool operator() (T0 lhs, T1 rhs) const
{
return lhs == static_cast<T0>(rhs);
}
};
template <typename T>
struct javascript_equal
{
javascript_equal(T const& lhs)
: lhs_(lhs) {}
bool operator() (T const& rhs) const
{
return util::apply_visitor(test::javascript_equal_visitor(), lhs_, rhs);
}
T const& lhs_;
};
} // namespace test
int main (/*int argc, char** argv*/)
{
typedef util::variant<bool, std::int64_t, std::uint64_t, double, std::string> variant_type;
variant_type v0(3.14159);
variant_type v1(std::string("3.14159"));
variant_type v2(std::uint64_t(1));
std::cerr << v0 << " == " << v1 << " -> "
<< std::boolalpha << util::apply_visitor(test::javascript_equal_visitor(), v0, v1) << std::endl;
std::vector<variant_type> vec;
vec.emplace_back(std::string("1"));
vec.push_back(variant_type(std::uint64_t(2)));
vec.push_back(variant_type(std::uint64_t(3)));
vec.push_back(std::string("3.14159"));
vec.emplace_back(3.14159);
//auto itr = std::find_if(vec.begin(), vec.end(), [&v0](variant_type const& val) {
// return util::apply_visitor(test::javascript_equal_visitor(), v0, val);
// });
auto itr = std::find_if(vec.begin(), vec.end(), test::javascript_equal<variant_type>(v2));
if (itr != std::end(vec))
{
std::cout << "found " << *itr << std::endl;
}
else
{
std::cout << "can't find " << v2 << '\n';
}
return EXIT_SUCCESS;
}

View File

@ -1,19 +0,0 @@
#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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,82 +0,0 @@
#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);
}

View File

@ -1,132 +0,0 @@
#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;
}

View File

@ -1,74 +0,0 @@
#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 point
{
public:
point (double x_, double y_)
: x(x_), y(y_) {}
double x;
double y;
};
struct line_string : std::vector<point> {};
struct polygon : std::vector<line_string> {};
using variant = util::variant<std::reference_wrapper<const point>,
std::reference_wrapper<const line_string>,
std::reference_wrapper<const polygon>>;
struct print
{
using result_type = void;
void operator() (point const& pt) const
{
std::cerr << "Point(" << pt.x << "," << pt.y << ")" << std::endl;
}
void operator() (line_string const& line) const
{
std::cerr << "Line(";
for (auto const& pt : line)
{
std::cerr << pt.x << " " << pt.y << ",";
}
std::cerr << ")" << std::endl;
}
template <typename T>
void operator() (T const& val) const
{
std::cerr << typeid(T).name() << std::endl;
}
};
}
int main (int argc, char** argv)
{
std::cerr << sizeof(test::polygon) << std::endl;
std::cerr << sizeof(test::variant) << std::endl;
test::point pt(123,456);
test::variant var = std::move(std::cref(pt));
util::apply_visitor(test::print(), var);
test::line_string line;
line.push_back(pt);
line.push_back(pt);
line.push_back(test::point(999,333));
var = std::move(std::cref(line));
util::apply_visitor(test::print(), var);
std::cerr << "Is line (cref) ? " << var.is<std::reference_wrapper<test::line_string const>>() << std::endl;
auto const& line2 = var.get<test::line_string>(); // accessing underlying type of std::reference_wrapper<T>
test::print printer;
printer(line2);
return EXIT_SUCCESS;
}

View File

@ -1,128 +0,0 @@
#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;
}

View File

@ -1,314 +0,0 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include "variant.hpp"
#include "variant_io.hpp"
#include <algorithm>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
using namespace mapbox;
template <typename T>
struct mutating_visitor
{
mutating_visitor(T & val)
: val_(val) {}
void operator() (T & val) const
{
val = val_;
}
template <typename T1>
void operator() (T1& ) const {} // no-op
T & val_;
};
TEST_CASE( "variant version", "[variant]" ) {
unsigned int version = VARIANT_VERSION;
REQUIRE(version == 100);
#if VARIANT_VERSION == 100
REQUIRE(true);
#else
REQUIRE(false);
#endif
}
TEST_CASE( "variant can be moved into vector", "[variant]" ) {
typedef util::variant<bool,std::string> variant_type;
variant_type v(std::string("test"));
std::vector<variant_type> vec;
vec.emplace_back(std::move(v));
REQUIRE(v.get<std::string>() != std::string("test"));
REQUIRE(vec.at(0).get<std::string>() == std::string("test"));
}
TEST_CASE( "variant should support built-in types", "[variant]" ) {
SECTION( "bool" ) {
util::variant<bool> v(true);
REQUIRE(v.valid());
REQUIRE(v.is<bool>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<bool>() == true);
v.set<bool>(false);
REQUIRE(v.get<bool>() == false);
v = true;
REQUIRE(v == util::variant<bool>(true));
}
SECTION( "nullptr" ) {
typedef std::nullptr_t value_type;
util::variant<value_type> v(nullptr);
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
// TODO: commented since it breaks on windows: 'operator << is ambiguous'
//REQUIRE(v.get<value_type>() == nullptr);
// FIXME: does not compile: ./variant.hpp:340:14: error: use of overloaded operator '<<' is ambiguous (with operand types 'std::__1::basic_ostream<char>' and 'const nullptr_t')
// https://github.com/mapbox/variant/issues/14
//REQUIRE(v == util::variant<value_type>(nullptr));
}
SECTION( "unique_ptr" ) {
typedef std::unique_ptr<std::string> value_type;
util::variant<value_type> v(value_type(new std::string("hello")));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(*v.get<value_type>().get() == *value_type(new std::string("hello")).get());
}
SECTION( "string" ) {
typedef std::string value_type;
util::variant<value_type> v(value_type("hello"));
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == value_type("hello"));
v.set<value_type>(value_type("there"));
REQUIRE(v.get<value_type>() == value_type("there"));
v = value_type("variant");
REQUIRE(v == util::variant<value_type>(value_type("variant")));
}
SECTION( "size_t" ) {
typedef std::size_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(value_type(0));
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int8_t" ) {
typedef std::int8_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int16_t" ) {
typedef std::int16_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int32_t" ) {
typedef std::int32_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
SECTION( "int64_t" ) {
typedef std::int64_t value_type;
util::variant<value_type> v(std::numeric_limits<value_type>::max());
REQUIRE(v.valid());
REQUIRE(v.is<value_type>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<value_type>() == std::numeric_limits<value_type>::max());
v.set<value_type>(0);
REQUIRE(v.get<value_type>() == value_type(0));
v = value_type(1);
REQUIRE(v == util::variant<value_type>(value_type(1)));
}
}
struct MissionInteger
{
typedef uint64_t value_type;
value_type val_;
public:
MissionInteger(uint64_t val) :
val_(val) {}
bool operator==(MissionInteger const& rhs) const
{
return (val_ == rhs.get());
}
uint64_t get() const
{
return val_;
}
};
// TODO - remove after https://github.com/mapbox/variant/issues/14
std::ostream& operator<<(std::ostream& os, MissionInteger const& rhs)
{
os << rhs.get();
return os;
}
TEST_CASE( "variant should support custom types", "[variant]" ) {
// http://www.missionintegers.com/integer/34838300
util::variant<MissionInteger> v(MissionInteger(34838300));
REQUIRE(v.valid());
REQUIRE(v.is<MissionInteger>());
REQUIRE(v.get_type_index() == 0);
REQUIRE(v.get<MissionInteger>() == MissionInteger(34838300));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(34838300));
// TODO: should both of the set usages below compile?
v.set<MissionInteger>(MissionInteger::value_type(0));
v.set<MissionInteger>(MissionInteger(0));
REQUIRE(v.get<MissionInteger>().get() == MissionInteger::value_type(0));
v = MissionInteger(1);
REQUIRE(v == util::variant<MissionInteger>(MissionInteger(1)));
}
// Test internal api
TEST_CASE( "variant should correctly index types", "[variant]" ) {
typedef util::variant<bool,std::string,std::uint64_t,std::int64_t,double,float> variant_type;
// Index is in reverse order
REQUIRE(variant_type(true).get_type_index() == 5);
REQUIRE(variant_type(std::string("test")).get_type_index() == 4);
REQUIRE(variant_type(std::uint64_t(0)).get_type_index() == 3);
REQUIRE(variant_type(std::int64_t(0)).get_type_index() == 2);
REQUIRE(variant_type(double(0.0)).get_type_index() == 1);
REQUIRE(variant_type(float(0.0)).get_type_index() == 0);
}
// Test internal api
TEST_CASE( "variant::which() returns zero based index of stored type", "[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).which() == 0);
REQUIRE(variant_type(std::string("test")).which() == 1);
REQUIRE(variant_type(std::uint64_t(0)).which() == 2);
REQUIRE(variant_type(std::int64_t(0)).which() == 3);
REQUIRE(variant_type(double(0.0)).which() == 4);
REQUIRE(variant_type(float(0.0)).which() == 5);
}
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);
}
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);
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>());
}
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;
}

View File

@ -1,22 +0,0 @@
#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;
}

View File

@ -1,21 +0,0 @@
{
"includes": [
"common.gypi"
],
"targets": [
{
"target_name": "tests",
"type": "executable",
"sources": [
"test/unit.cpp"
],
"xcode_settings": {
"SDKROOT": "macosx",
"SUPPORTED_PLATFORMS":["macosx"]
},
"include_dirs": [
"./"
]
}
]
}

View File

@ -1,886 +0,0 @@
#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;
};
// check if T is in Types...
template <typename T, typename...Types>
struct has_type;
template <typename T, typename First, typename... Types>
struct has_type<T, First, Types...>
{
static constexpr bool value = std::is_same<T, First>::value
|| has_type<T, Types...>::value;
};
template <typename T>
struct has_type<T> : std::false_type {};
//
template <typename T, typename...Types>
struct is_valid_type;
template <typename T, typename First, typename... Types>
struct is_valid_type<T, First, Types...>
{
static constexpr bool value = std::is_convertible<T, First>::value
|| is_valid_type<T, Types...>::value;
};
template <typename T>
struct is_valid_type<T> : std::false_type {};
template <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);
}
}
VARIANT_INLINE static void direct_swap(const std::size_t id, void * lhs, void * rhs)
{
using std::swap; //enable ADL
if (id == sizeof...(Types))
{
// both lhs and rhs hold T
swap(*reinterpret_cast<T*>(lhs), *reinterpret_cast<T*>(rhs));
}
else
{
variant_helper<Types...>::direct_swap(id, lhs, rhs);
}
}
};
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 *) {}
VARIANT_INLINE static void direct_swap(const std::size_t, 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 T>
struct unwrapper<std::reference_wrapper<T>>
{
auto operator() (std::reference_wrapper<T> const& obj) const
-> typename std::reference_wrapper<T>::type const&
{
return obj.get();
}
};
template <typename F, typename V, typename R, typename...Types>
struct dispatcher;
template <typename F, typename V, typename R, typename T, typename...Types>
struct dispatcher<F, V, R, T, Types...>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& v, F f)
{
if (v.get_type_index() == sizeof...(Types))
{
return f(unwrapper<T>()(v. template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply_const(v, f);
}
}
VARIANT_INLINE static result_type apply(V & v, F f)
{
if (v.get_type_index() == sizeof...(Types))
{
return f(unwrapper<T>()(v. template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply(v, f);
}
}
};
template<typename F, typename V, typename R>
struct dispatcher<F, V, R>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, F)
{
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
}
VARIANT_INLINE static result_type apply(V &, F)
{
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
}
};
template <typename F, typename V, typename R, typename T, typename...Types>
struct binary_dispatcher_rhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
{
return f(unwrapper<T0>()(lhs. template get<T0>()),
unwrapper<T1>()(rhs. template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
}
}
VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
{
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
{
return f(unwrapper<T0>()(lhs. template get<T0>()),
unwrapper<T1>()(rhs. template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
}
}
};
template<typename F, typename V, typename R, typename T>
struct binary_dispatcher_rhs<F, V, R, T>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
VARIANT_INLINE static result_type apply(V &, V &, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
};
template <typename F, typename V, typename R, typename T, typename...Types>
struct binary_dispatcher_lhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename...Types>
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
{
return f(lhs. template get<T1>(), rhs. template get<T0>());
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, f);
}
}
VARIANT_INLINE static result_type apply(V & lhs, V & rhs, F f)
{
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
{
return f(lhs. template get<T1>(), rhs. template get<T0>());
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, f);
}
}
};
template<typename F, typename V, typename R, typename T>
struct binary_dispatcher_lhs<F, V, R, T>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
VARIANT_INLINE static result_type apply(V &, V &, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
};
template <typename F, typename V, typename R, typename...Types>
struct binary_dispatcher;
template <typename F, typename V, typename R, typename T, typename...Types>
struct binary_dispatcher<F, V, R, T, Types...>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
{
if (v0.get_type_index() == sizeof...(Types))
{
if (v0.get_type_index() == v1.get_type_index())
{
return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
}
}
else if (v1.get_type_index() == sizeof...(Types))
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, f);
}
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
}
VARIANT_INLINE static result_type apply(V & v0, V & v1, F f)
{
if (v0.get_type_index() == sizeof...(Types))
{
if (v0.get_type_index() == v1.get_type_index())
{
return f(v0. template get<T>(), v1. template get<T>()); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, f);
}
}
else if (v1.get_type_index() == sizeof...(Types))
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, f);
}
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
}
};
template<typename F, typename V, typename R>
struct binary_dispatcher<F, V, R>
{
using result_type = R;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
VARIANT_INLINE static result_type apply(V &, V &, F)
{
throw std::runtime_error("binary dispatch: FAIL");
}
};
// comparator functors
struct equal_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs == rhs;
}
};
struct less_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs < rhs;
}
};
template <typename Variant, typename Comp>
class comparer
{
public:
explicit comparer(Variant const& lhs) noexcept
: lhs_(lhs) {}
comparer& operator=(comparer const&) = delete;
// visitor
template<typename T>
bool operator()(T const& rhs_content) const
{
T const& lhs_content = lhs_.template get<T>();
return Comp()(lhs_content, rhs_content);
}
private:
Variant const& lhs_;
};
} // namespace detail
struct no_init {};
template<typename... Types>
class variant
{
private:
static const std::size_t data_size = static_max<sizeof(Types)...>::value;
static const std::size_t data_align = static_max<alignof(Types)...>::value;
using data_type = typename std::aligned_storage<data_size, data_align>::type;
using helper_type = variant_helper<Types...>;
std::size_t type_index;
data_type data;
public:
VARIANT_INLINE variant()
: type_index(sizeof...(Types) - 1)
{
new (&data) typename detail::select_type<0, Types...>::type();
}
VARIANT_INLINE variant(no_init)
: type_index(detail::invalid_value) {}
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
template <typename T, class = typename std::enable_if<
detail::is_valid_type<typename std::remove_reference<T>::type, Types...>::value>::type>
VARIANT_INLINE variant(T && val) noexcept
: type_index(detail::value_traits<typename std::remove_reference<T>::type, Types...>::index)
{
constexpr std::size_t index = sizeof...(Types) - detail::value_traits<typename std::remove_reference<T>::type, Types...>::index - 1;
using target_type = typename detail::select_type<index, Types...>::type;
new (&data) target_type(std::forward<T>(val)); // nothrow
}
VARIANT_INLINE variant(variant<Types...> const& old)
: type_index(old.type_index)
{
helper_type::copy(old.type_index, &old.data, &data);
}
VARIANT_INLINE variant(variant<Types...>&& old) noexcept
: type_index(old.type_index)
{
helper_type::move(old.type_index, &old.data, &data);
}
private:
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::copy(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
VARIANT_INLINE void move_assign(variant<Types...> && rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::move(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
public:
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> && other)
{
move_assign(std::move(other));
return *this;
}
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
{
copy_assign(other);
return *this;
}
// conversions
// move-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T && rhs) noexcept
{
variant<Types...> temp(std::forward<T>(rhs));
move_assign(std::move(temp));
return *this;
}
// copy-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
{
variant<Types...> temp(rhs);
copy_assign(temp);
return *this;
}
template<typename T>
VARIANT_INLINE bool is() const
{
static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
return (type_index == detail::direct_type<T, Types...>::index);
}
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;
}
// get<T>()
template<typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)
>::type* = nullptr>
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<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)
>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<T, Types...>::index)
{
return *reinterpret_cast<T const*>(&data);
}
else
{
throw std::runtime_error("in get<T>()");
}
}
// get<T>() - T stored as recursive_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
}
else
{
throw std::runtime_error("in get<T>()");
}
}
template <typename T,typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)
>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
}
else
{
throw std::runtime_error("in get<T>()");
}
}
// get<T>() - T stored as std::reference_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)
>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
}
else
{
throw std::runtime_error("in get<T>()");
}
}
template <typename T,typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)
>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
}
else
{
throw std::runtime_error("in get<T>()");
}
}
VARIANT_INLINE std::size_t get_type_index() const
{
return type_index;
}
VARIANT_INLINE int which() const noexcept
{
return static_cast<int>(sizeof...(Types) - type_index - 1);
}
// visitor
// unary
template <typename F, typename V>
auto VARIANT_INLINE
static visit(V const& v, F f)
-> decltype(detail::dispatcher<F, V,
typename detail::result_of_unary_visit<F,
typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v, f))
{
using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
return detail::dispatcher<F, V, R, Types...>::apply_const(v, f);
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE
static visit(V & v, F f)
-> decltype(detail::dispatcher<F, V,
typename detail::result_of_unary_visit<F,
typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v, f))
{
using R = typename detail::result_of_unary_visit<F, typename detail::select_type<0, Types...>::type>::type;
return detail::dispatcher<F, V, R, Types...>::apply(v, f);
}
// binary
// const
template <typename F, typename V>
auto VARIANT_INLINE
static binary_visit(V const& v0, V const& v1, F f)
-> decltype(detail::binary_dispatcher<F, V,
typename detail::result_of_binary_visit<F,
typename detail::select_type<0, Types...>::type>::type, Types...>::apply_const(v0, v1, f))
{
using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, f);
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE
static binary_visit(V& v0, V& v1, F f)
-> decltype(detail::binary_dispatcher<F, V,
typename detail::result_of_binary_visit<F,
typename detail::select_type<0, Types...>::type>::type, Types...>::apply(v0, v1, f))
{
using R = typename detail::result_of_binary_visit<F,typename detail::select_type<0, Types...>::type>::type;
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, f);
}
~variant() noexcept
{
helper_type::destroy(type_index, &data);
}
// comparison operators
// equality
VARIANT_INLINE bool operator==(variant const& rhs) const
{
if (this->get_type_index() != rhs.get_type_index())
return false;
detail::comparer<variant, detail::equal_comp> visitor(*this);
return visit(rhs, visitor);
}
// less than
VARIANT_INLINE bool operator<(variant const& rhs) const
{
if (this->get_type_index() != rhs.get_type_index())
{
return this->get_type_index() < rhs.get_type_index();
// ^^ borrowed from boost::variant
}
detail::comparer<variant, detail::less_comp> visitor(*this);
return visit(rhs, visitor);
}
};
// unary visitor interface
// const
template <typename V, typename F>
auto VARIANT_INLINE static apply_visitor(F f, V const& v) -> decltype(V::visit(v, f))
{
return V::visit(v, f);
}
// non-const
template <typename V, typename F>
auto VARIANT_INLINE static apply_visitor(F f, V & v) -> decltype(V::visit(v, f))
{
return V::visit(v, f);
}
// binary visitor interface
// const
template <typename V, typename F>
auto VARIANT_INLINE static apply_visitor(F f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, f))
{
return V::binary_visit(v0, v1, f);
}
// non-const
template <typename V, typename F>
auto VARIANT_INLINE static apply_visitor(F f, V & v0, V & v1) -> decltype(V::binary_visit(v0, v1, f))
{
return V::binary_visit(v0, v1, f);
}
// getter interface
template<typename ResultType, typename T>
ResultType & get(T & var)
{
return var.template get<ResultType>();
}
template<typename ResultType, typename T>
ResultType const& get(T const& var)
{
return var.template get<ResultType>();
}
}}
#endif // MAPBOX_UTIL_VARIANT_HPP

View File

@ -1,39 +0,0 @@
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
#define MAPBOX_UTIL_VARIANT_IO_HPP
namespace mapbox { namespace util {
namespace detail {
// operator<< helper
template <typename Out>
class printer
{
public:
explicit printer(Out & out)
: out_(out) {}
printer& operator=(printer const&) = delete;
// visitor
template <typename T>
void operator()(T const& operand) const
{
out_ << operand;
}
private:
Out & out_;
};
}
// operator<<
template <typename charT, typename traits, typename... Types>
VARIANT_INLINE std::basic_ostream<charT, traits>&
operator<< (std::basic_ostream<charT, traits>& out, variant<Types...> const& rhs)
{
detail::printer<std::basic_ostream<charT, traits>> visitor(out);
apply_visitor(visitor, rhs);
return out;
}
}}
#endif //MAPBOX_UTIL_VARIANT_IO_HPP

View File

@ -1,8 +0,0 @@
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