Commit df11c004 authored by Kenneth Leiter's avatar Kenneth Leiter

Replace boost::variant with mapbox variant

parent e2c1238a
This diff is collapsed.
......@@ -39,8 +39,7 @@ class XdmfHeavyDataController;
#include <memory>
// Includes
#include <boost/variant.hpp>
using boost::variant;
#include "mapbox/variant.hpp"
/**
* @brief Provides storage for data values that are read in or will be
......@@ -1504,8 +1503,10 @@ private:
*/
void internalizeArrayPointer();
typedef variant<
boost::blank,
struct Empty {};
typedef mapbox::util::variant<
Empty,
shared_ptr<std::vector<char> >,
shared_ptr<std::vector<short> >,
shared_ptr<std::vector<int> >,
......
This diff is collapsed.
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.
\ No newline at end of file
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# Mapbox Variant
An header-only alternative to `boost::variant` for C++11 and C++14
[![Build Status](https://secure.travis-ci.org/mapbox/variant.svg)](https://travis-ci.org/mapbox/variant)
[![Build status](https://ci.appveyor.com/api/projects/status/v9tatx21j1k0fcgy)](https://ci.appveyor.com/project/Mapbox/variant)
[![Coverage Status](https://coveralls.io/repos/mapbox/variant/badge.svg?branch=master&service=github)](https://coveralls.io/r/mapbox/variant?branch=master)
## Introduction
Variant's basic building blocks are:
- `variant<Ts...>` - a type-safe representation for sum-types / discriminated unions
- `recursive_wrapper<T>` - a helper type to represent recursive "tree-like" variants
- `apply_visitor(visitor, myVariant)` - to invoke a custom visitor on the variant's underlying type
- `get<T>()` - a function to directly unwrap a variant's underlying type
- `.match([](Type){})` - a variant convenience member function taking an arbitrary number of lambdas creating a visitor behind the scenes and applying it to the variant
### Basic Usage - HTTP API Example
Suppose you want to represent a HTTP API response which is either a JSON result or an error:
```c++
struct Result {
Json object;
};
struct Error {
int32_t code;
string message;
};
```
You can represent this at type level using a variant which is either an `Error` or a `Result`:
```c++
using Response = variant<Error, Result>;
Response makeRequest() {
return Error{501, "Not Implemented"};
}
Response ret = makeRequest();
```
To see which type the `Response` holds you pattern match on the variant unwrapping the underlying value:
```c++
ret.match([] (Result r) { print(r.object); },
[] (Error e) { print(e.message); });
```
Instead of using the variant's convenience `.match` pattern matching function you can create a type visitor functor and use `apply_visitor` manually:
```c++
struct ResponseVisitor {
void operator()(Result r) const {
print(r.object);
}
void operator()(Error e) const {
print(e.message);
}
};
ResponseVisitor visitor;
apply_visitor(visitor, ret);
```
In both cases the compiler makes sure you handle all types the variant can represent at compile.
### Recursive Variants - JSON Example
[JSON](http://www.json.org/) consists of types `String`, `Number`, `True`, `False`, `Null`, `Array` and `Object`.
```c++
struct String { string value; };
struct Number { double value; };
struct True { };
struct False { };
struct Null { };
struct Array { vector<?> values; };
struct Object { unordered_map<string, ?> values; };
```
This works for primitive types but how do we represent recursive types such as `Array` which can hold multiple elements and `Array` itself, too?
For these use cases Variant provides a `recursive_wrapper` helper type which lets you express recursive Variants.
```c++
struct String { string value; };
struct Number { double value; };
struct True { };
struct False { };
struct Null { };
// Forward declarations only
struct Array;
struct Object;
using Value = variant<String, Number, True, False, Null, recursive_wrapper<Array>, recursive_wrapper<Object>>;
struct Array {
vector<Value> values;
};
struct Object {
unordered_map<string, Value> values;
};
```
For walkig the JSON representation you can again either create a `JSONVisitor`:
```c++
struct JSONVisitor {
void operator()(Null) const {
print("null");
}
// same for all other JSON types
};
JSONVisitor visitor;
apply_visitor(visitor, json);
```
Or use the convenience `.match` pattern matching function:
```c++
json.match([] (Null) { print("null"); },
...);
```
To summarize: use `recursive_wrapper` to represent recursive "tree-like" representations:
```c++
struct Empty { };
struct Node;
using Tree = variant<Empty, recursive_wrapper<Node>>;
struct Node {
uint64_t value;
}
```
### Advanced Usage Tips
Creating type aliases for variants is a great way to reduce repetition.
Keep in mind those type aliases are not checked at type level, though.
We recommend creating a new type for all but basic variant usage:
```c++
// the compiler can't tell the following two apart
using APIResult = variant<Error, Result>;
using FilesystemResult = variant<Error, Result>;
// new type
struct APIResult : variant<Error, Result> {
using Base = variant<Error, Result>;
using Base::Base;
}
```
## 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
(Numbers from an older version of Mapbox variant.)
## Goals
Mapbox `variant` has been a very valuable, lightweight alternative for apps
that can use c++11 or c++14 but that do not want a boost dependency.
Mapbox `variant` has also been useful in apps that do depend on boost, like
mapnik, to help (slightly) with compile times and to majorly lessen dependence
on boost in core headers. The original goal and near term goal is to maintain
external API compatibility with `boost::variant` such that Mapbox `variant`
can be a "drop in". At the same time the goal is to stay minimal: Only
implement the features that are actually needed in existing software. So being
an "incomplete" implementation is just fine.
Currently Mapbox variant doesn't try to be API compatible with the upcoming
variant standard, because the standard is not finished and it would be too much
work. But we'll revisit this decision in the future if needed.
If Mapbox variant is not for you, have a look at [these other
implementations](doc/other_implementations.md).
Want to know more about the upcoming standard? Have a look at our
[overview](doc/standards_effort.md).
Most modern high-level languages provide ways to express sum types directly.
If you're curious have a look at Haskell's pattern matching or Rust's and Swift's enums.
## Depends
- Compiler supporting `-std=c++11` or `-std=c++14`
Tested with:
- g++-4.7
- g++-4.8
- g++-4.9
- g++-5.2
- clang++-3.5
- clang++-3.6
- clang++-3.7
- clang++-3.8
- clang++-3.9
- Visual Studio 2015
## Unit Tests
On Unix systems compile and run the unit tests with `make test`.
On Windows run `scripts/build-local.bat`.
## Limitations
* The `variant` can not hold references (something like `variant<int&>` is
not possible). You might want to try `std::reference_wrapper` instead.
## Deprecations
* The included implementation of `optional` is deprecated and will be removed
in a future version. See https://github.com/mapbox/variant/issues/64.
* Old versions of the code needed visitors to derive from `static_visitor`.
This is not needed any more and marked as deprecated. The `static_visitor`
class will be removed in future versions.
## Benchmarks
make bench
## Check object sizes
make sizes /path/to/boost/variant.hpp
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
#define MAPBOX_UTIL_OPTIONAL_HPP
#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
#include <type_traits>
#include <utility>
#include <mapbox/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{}; }
}; // class optional
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_OPTIONAL_HPP
{
"name": "variant",
"version": "1.3.0",
"description": "C++11/C++14 variant",
"main": "./package.json",
"repository" : {
"type" : "git",
"url" : "git://github.com/mapbox/variant.git"
}
}
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
// Based on variant/recursive_wrapper.hpp from boost.
//
// Original license:
//
// Copyright (c) 2002-2003
// Eric Friedman, Itay Maman
//
// 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)
#include <cassert>
#include <utility>
namespace mapbox {
namespace util {
template <typename T>
class recursive_wrapper
{
T* p_;
void assign(T const& rhs)
{
this->get() = rhs;
}
public:
using type = T;
/**
* Default constructor default initializes the internally stored value.
* For POD types this means nothing is done and the storage is
* uninitialized.
*
* @throws std::bad_alloc if there is insufficient memory for an object
* of type T.
* @throws any exception thrown by the default constructur of T.
*/
recursive_wrapper()
: p_(new T){}
~recursive_wrapper() noexcept { delete p_; }
recursive_wrapper(recursive_wrapper const& operand)
: p_(new T(operand.get())) {}
recursive_wrapper(T const& operand)
: p_(new T(operand)) {}
recursive_wrapper(recursive_wrapper&& operand)
: p_(new T(std::move(operand.get()))) {}
recursive_wrapper(T&& operand)
: p_(new T(std::move(operand))) {}
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;
}
T& get()
{
assert(p_);
return *get_pointer();
}
T const& get() const
{
assert(p_);
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(); }
}; // class recursive_wrapper
template <typename T>
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
This diff is collapsed.
#ifndef VARIANT_CAST_HPP
#define VARIANT_CAST_HPP
#include <type_traits>
namespace mapbox {
namespace util {
namespace detail {
template <class T>
class static_caster
{
public:
template <class V>
T& operator()(V& v) const
{
return static_cast<T&>(v);
}
};
template <class T>
class dynamic_caster
{
public:
using result_type = T&;
template <class V>
T& operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const
{
throw std::bad_cast();
}
template <class V>
T& operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const
{
return dynamic_cast<T&>(v);
}
};
template <class T>
class dynamic_caster<T*>
{
public:
using result_type = T*;
template <class V>
T* operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const
{
return nullptr;
}
template <class V>
T* operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const
{
return dynamic_cast<T*>(&v);
}
};
}
template <class T, class V>
typename detail::dynamic_caster<T>::result_type
dynamic_variant_cast(V& v)
{
return mapbox::util::apply_visitor(detail::dynamic_caster<T>(), v);
}
template <class T, class V>
typename detail::dynamic_caster<const T>::result_type
dynamic_variant_cast(const V& v)
{
return mapbox::util::apply_visitor(detail::dynamic_caster<const T>(), v);
}
template <class T, class V>
T& static_variant_cast(V& v)
{
return mapbox::util::apply_visitor(detail::static_caster<T>(), v);
}
template <class T, class V>
const T& static_variant_cast(const V& v)
{
return mapbox::util::apply_visitor(detail::static_caster<const T>(), v);
}
}
}
#endif // VARIANT_CAST_HPP
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
#define MAPBOX_UTIL_VARIANT_IO_HPP
#include <iosfwd>
#include <mapbox/variant.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;
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_IO_HPP
#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
#define MAPBOX_UTIL_VARIANT_VISITOR_HPP
#include <utility>
namespace mapbox {
namespace util {
template <typename... Fns>
struct visitor;
template <typename Fn>
struct visitor<Fn> : Fn
{
using Fn::operator();
template<typename T>
visitor(T&& fn) : Fn(std::forward<T>(fn)) {}
};
template <typename Fn, typename... Fns>
struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
{
using Fn::operator();
using visitor<Fns...>::operator();
template<typename T, typename... Ts>
visitor(T&& fn, Ts&&... fns)
: Fn(std::forward<T>(fn))
, visitor<Fns...>(std::forward<Ts>(fns)...) {}
};
template <typename... Fns>
visitor<typename std::decay<Fns>::type...> make_visitor(Fns&&... fns)
{
return visitor<typename std::decay<Fns>::type...>
(std::forward<Fns>(fns)...);
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP
#include <cstdio>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <exodusII.h>
#include "XdmfDomain.hpp"
#include "XdmfError.hpp"
......
......@@ -22,11 +22,13 @@
/*****************************************************************************/
#include <exodusII.h>
#include <algorithm>
#include <cstring>
#include "XdmfArrayType.hpp"
#include "XdmfAttribute.hpp"
#include "XdmfAttributeCenter.hpp"
#include "XdmfAttributeType.hpp"
#include "XdmfError.hpp"
#include "XdmfExodusReader.hpp"
#include "XdmfGeometry.hpp"
#include "XdmfGeometryType.hpp"
......@@ -36,7 +38,6 @@
#include "XdmfTopology.hpp"
#include "XdmfTopologyType.hpp"
#include "XdmfUnstructuredGrid.hpp"
#include "XdmfError.hpp"