Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LDFLAGS := $(LDFLAGS)

ALL_HEADERS = $(shell find include/mapbox/ '(' -name '*.hpp' ')')

all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
all: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test out/boost_spirit_karma out/boost_spirit_qi

mason_packages:
git submodule update --init .mason
Expand Down Expand Up @@ -47,6 +47,14 @@ out/binary_visitor_test: Makefile mason_packages test/binary_visitor_test.cpp
mkdir -p ./out
$(CXX) -o out/binary_visitor_test test/binary_visitor_test.cpp -I./include -Itest/include $(RELEASE_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)

out/boost_spirit_qi:
mkdir -p ./out
$(CXX) -o out/boost_spirit_qi test/boost_spirit_qi.cpp -I./include -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)

out/boost_spirit_karma:
mkdir -p ./out
$(CXX) -o out/boost_spirit_karma test/boost_spirit_karma.cpp -I./include -Itest/include $(DEBUG_FLAGS) $(COMMON_FLAGS) $(CXXFLAGS) $(LDFLAGS) $(BOOST_FLAGS)

bench: out/bench-variant out/unique_ptr_test out/unique_ptr_test out/recursive_wrapper_test out/binary_visitor_test
./out/bench-variant 100000
./out/unique_ptr_test 100000
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ Tested with:
There is nothing to build, just include `variant.hpp` in your project. Include `variant_io.hpp` if you need
the `operator<<` overload for variant.

### Usage with Boost.Spirit
If you want to use MapBox.Variant with the [Boost.Spirit](http://www.boost.org/doc/libs/release/libs/spirit/doc/html/index.html) library, you can simply use the following supporting headers :

* `#include <mapbox/boost_spirit_qi.hpp>`
* `#include <mapbox/boost_spirit_karma.hpp>`

Examples are available here : [Boost.Spirit.Qi](test/boost_spirit_qi.cpp), [Boost.Spirit.Karma](test/boost_spirit_karma.cpp).

## Unit Tests

Expand Down
14 changes: 14 additions & 0 deletions include/mapbox/boost_spirit_karma.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2016 Damien Buhl (alias daminetreg) for Fr. Sauter AG, CH-4016 BASEL
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MAPBOX_BOOST_SPIRIT_KARMA_HPP
#define MAPBOX_BOOST_SPIRIT_KARMA_HPP

#include <mapbox/variant.hpp>

namespace boost { using mapbox::util::get; }

#include <mapbox/detail/boost_spirit_attributes.hpp>

#endif
25 changes: 25 additions & 0 deletions include/mapbox/boost_spirit_qi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2016 Damien Buhl (alias daminetreg) for Fr. Sauter AG, CH-4016 BASEL
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MAPBOX_BOOST_SPIRIT_QI_HPP
#define MAPBOX_BOOST_SPIRIT_QI_HPP

#include <mapbox/detail/boost_spirit_attributes.hpp>

#include <boost/spirit/include/qi_alternative.hpp>

namespace boost { namespace spirit { namespace qi { namespace detail
{
template <typename Expected, class... Types>
struct find_substitute<mapbox::util::variant<Types...>, Expected>
{
// Get the typr from the variant that can be a substitute for Expected.
// If none is found, just return Expected

typedef Expected type;
};
}}}}


#endif
67 changes: 67 additions & 0 deletions include/mapbox/detail/boost_spirit_attributes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2016 Damien Buhl (alias daminetreg) for Fr. Sauter AG, CH-4016 BASEL
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MAPBOX_DETAIL_BOOST_SPIRIT_ATTRIBUTES_HPP
#define MAPBOX_DETAIL_BOOST_SPIRIT_ATTRIBUTES_HPP

#include <mapbox/variant.hpp>

#include <mapbox/traits/is_mapbox_variant.hpp>
#include <mapbox/traits/is_type_in_variant.hpp>

#include <boost/spirit/home/support/attributes.hpp>

// Defines the trait for Boost.Spirit to treat mapbox::util::variant as a variant.
namespace boost { namespace spirit { namespace traits
{
template <typename Domain, class... Types>
struct not_is_variant<mapbox::util::variant<Types...>, Domain>
: mpl::false_
{};
}
}}

namespace boost { namespace spirit { namespace traits {

template <class... Types>
struct variant_which< mapbox::util::variant<Types...> >
{
static int call(mapbox::util::variant<Types...> const& v)
{
return v.which();
}
};

}}}

namespace boost { namespace spirit { namespace traits {

template <typename Variant, typename Expected>
struct compute_compatible_component_variant<Variant, Expected, mpl::false_
, typename enable_if< typename mapbox::traits::is_mapbox_variant<Variant>::type >::type>
{
typedef typename traits::variant_type<Variant>::type variant_type;

// true_ if the attribute matches one of the types in the variant
typedef mapbox::traits::is_type_in_variant<Expected, Variant> type;
enum { value = type::value };

// return the type in the variant the attribute is compatible with
typedef typename
mpl::eval_if<type, mpl::identity<Expected>, mpl::identity<unused_type> >::type
compatible_type;

// return whether the given type is compatible with the Expected type
static bool is_compatible(int which)
{
auto idx = (type::size - 1 - type::index); // Typelist is inverted and 0-based
return which == idx;
}
};


}}}


#endif
33 changes: 33 additions & 0 deletions include/mapbox/traits/is_mapbox_variant.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2016 Damien Buhl (alias daminetreg) for Fr. Sauter AG, CH-4016 BASEL
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MAPBOX_TRAITS_IS_MAPBOX_VARIANT_HPP
#define MAPBOX_TRAITS_IS_MAPBOX_VARIANT_HPP

#include <mapbox/variant.hpp>

namespace mapbox { namespace traits {

template <class... Types>
struct is_mapbox_variant {
using type = std::false_type;
enum { value = false };
};

template <class... Types>
struct is_mapbox_variant<mapbox::util::variant<Types...>> {
using type = std::true_type;
enum { value = true };
};

template <class... Types>
struct is_mapbox_variant<const mapbox::util::variant<Types...>> {
using type = std::true_type;
enum { value = true };
};


}}

#endif
30 changes: 30 additions & 0 deletions include/mapbox/traits/is_type_in_variant.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2016 Damien Buhl (alias daminetreg) for Fr. Sauter AG, CH-4016 BASEL
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef MAPBOX_TRAITS_IS_TYPE_IN_VARIANT_HPP
#define MAPBOX_TRAITS_IS_TYPE_IN_VARIANT_HPP

#include <mapbox/variant.hpp>

namespace mapbox { namespace traits {

template <class T, class... Types>
struct is_type_in_variant;

template <class T, class... Types>
struct is_type_in_variant<T, mapbox::util::variant<Types...>> {

using variant = mapbox::util::variant<Types...>;
using direct_type = mapbox::util::detail::direct_type<T, Types...>;

using type = std::integral_constant<bool, (direct_type::index != mapbox::util::detail::invalid_value)>;
enum { value = type::value };

enum { index = direct_type::index };
enum { size = sizeof...(Types) };
};

}}

#endif
58 changes: 58 additions & 0 deletions test/boost_spirit_karma.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <iostream>
#include <cassert>

#include <mapbox/variant.hpp>
#include <mapbox/boost_spirit_karma.hpp>
#include <boost/spirit/include/karma.hpp>

typedef mapbox::util::variant<int, bool, std::string, float, long, uint64_t> frame;

int main() {
typedef std::back_insert_iterator<std::string> Iterator;

using namespace boost::spirit::karma;

rule<Iterator, std::string()> mystring = *char_;

rule<Iterator, frame()> r =
int_
| bool_
| mystring
;


{
frame frm = 12;
std::string buf;
Iterator iter(buf);
auto s = generate(iter, r, frm);

std::cout << (s ? " success " : " error ") << " - " << mapbox::util::get<int>(frm) << " == " << buf << std::endl;
assert(s);
assert("12" == buf);
}

{
frame frm = true;
std::string buf;
Iterator iter(buf);
auto s = generate(iter, r, frm);

std::cout << (s ? " success " : " error ") << " - " << mapbox::util::get<bool>(frm) << " == " << buf << std::endl;
assert(s);
assert("true" == buf);
}

{
frame frm = std::string{"this is a string"};
std::string buf;
Iterator iter(buf);
auto s = generate(iter, r, frm);

std::cout << (s ? " success " : " error ") << " - " << mapbox::util::get<std::string>(frm) << " == " << buf << std::endl;
assert(s);
assert("this is a string" == buf);
}

return EXIT_SUCCESS;
}
63 changes: 63 additions & 0 deletions test/boost_spirit_qi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <iostream>
#include <typeinfo>
#include <cassert>

#include <mapbox/variant.hpp>
#include <mapbox/boost_spirit_qi.hpp>
#include <boost/spirit/include/qi.hpp>

typedef mapbox::util::variant<int, bool, std::string> frame;

struct parse_asserter {

frame _expected;
parse_asserter(frame expected)
: _expected(expected) {}

template <typename T>
void operator()(T const& val) const
{
std::cout << typeid(T).name() << " " << val << std::endl;
assert(mapbox::util::get<T>(_expected) == val);
}

};

int main() {
typedef std::string::const_iterator Iterator;

using namespace boost::spirit::qi;

rule<Iterator, frame()> r =
int_
| bool_
| as_string[*char_]
;

{
frame frm{};
const std::string text = "this is a string";

assert( parse(text.cbegin(), text.cend(), r, frm) );
mapbox::util::apply_visitor(parse_asserter{text}, frm);
}

{
frame frm{};
const std::string text = "42";

assert( parse(text.cbegin(), text.cend(), r, frm) );
mapbox::util::apply_visitor(parse_asserter{42}, frm);
}

{
frame frm{};
const std::string text = "true";

assert( parse(text.cbegin(), text.cend(), r, frm) );
mapbox::util::apply_visitor(parse_asserter{true}, frm);
}


return EXIT_SUCCESS;
}