summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-06-27 18:10:48 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-06-27 18:10:48 -0700
commit63c2e854ed2c9778ea9225d86578b4e9b65900ee (patch)
treebcd4dd86155ec59288e11b9a2bfcdebfc64f766f
parent23c6155f8e6ce93f41597e7aa860cca0b5110e4b (diff)
downloadtmwa-63c2e854ed2c9778ea9225d86578b4e9b65900ee.tar.gz
tmwa-63c2e854ed2c9778ea9225d86578b4e9b65900ee.tar.bz2
tmwa-63c2e854ed2c9778ea9225d86578b4e9b65900ee.tar.xz
tmwa-63c2e854ed2c9778ea9225d86578b4e9b65900ee.zip
Port the Variant junk
-rw-r--r--src/sexpr/bind.cpp29
-rw-r--r--src/sexpr/bind.hpp51
-rw-r--r--src/sexpr/lexer.hpp2
-rw-r--r--src/sexpr/parser.hpp2
-rw-r--r--src/sexpr/union.cpp44
-rw-r--r--src/sexpr/union.hpp108
-rw-r--r--src/sexpr/variant.cpp40
-rw-r--r--src/sexpr/variant.hpp119
-rw-r--r--src/sexpr/variant.tcc293
-rw-r--r--src/sexpr/variant_test.cpp125
-rw-r--r--src/sexpr/void.cpp29
-rw-r--r--src/sexpr/void.hpp43
12 files changed, 885 insertions, 0 deletions
diff --git a/src/sexpr/bind.cpp b/src/sexpr/bind.cpp
new file mode 100644
index 0000000..d8d0caa
--- /dev/null
+++ b/src/sexpr/bind.cpp
@@ -0,0 +1,29 @@
+#include "bind.hpp"
+// bind.cpp - Just include the header file.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+} // namespace sexpr
+} // namespace tmwa
diff --git a/src/sexpr/bind.hpp b/src/sexpr/bind.hpp
new file mode 100644
index 0000000..7250f9d
--- /dev/null
+++ b/src/sexpr/bind.hpp
@@ -0,0 +1,51 @@
+#ifndef TMWA_SEXPR_BIND_HPP
+#define TMWA_SEXPR_BIND_HPP
+// bind.hpp - Like std::bind, but with arbitrary arguments.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# include <utility>
+
+# include "fwd.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+ template<class F, class T>
+ struct VariadicBind
+ {
+ // note: may be lvalue references
+ F&& f;
+ T&& t;
+ template<class... A>
+ auto operator()(A&&... a) -> decltype(std::forward<F>(f)(std::forward<T>(t), std::forward<A>(a)...))
+ {
+ return std::forward<F>(f)(std::forward<T>(t), std::forward<A>(a)...);
+ }
+ };
+ template<class F, class T>
+ VariadicBind<F, T> bind_variadic(F&& func, T&& arg1)
+ {
+ return VariadicBind<F, T>{std::forward<F>(func), std::forward<T>(arg1)};
+ }
+} // namespace sexpr
+} // namespace tmwa
+
+#endif //TMWA_SEXPR_VARIANT_HPP
diff --git a/src/sexpr/lexer.hpp b/src/sexpr/lexer.hpp
index d1c4643..bd7b532 100644
--- a/src/sexpr/lexer.hpp
+++ b/src/sexpr/lexer.hpp
@@ -29,6 +29,8 @@
# include "../io/line.hpp"
+# include "fwd.hpp"
+
namespace tmwa
{
diff --git a/src/sexpr/parser.hpp b/src/sexpr/parser.hpp
index 2404a9a..c787e56 100644
--- a/src/sexpr/parser.hpp
+++ b/src/sexpr/parser.hpp
@@ -29,6 +29,8 @@
# include "lexer.hpp"
+# include "fwd.hpp"
+
namespace tmwa
{
diff --git a/src/sexpr/union.cpp b/src/sexpr/union.cpp
new file mode 100644
index 0000000..6f65012
--- /dev/null
+++ b/src/sexpr/union.cpp
@@ -0,0 +1,44 @@
+#include "union.hpp"
+// union.cpp - Just include the header file and try to instantiate.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+namespace
+{
+ struct Foo
+ {
+ Foo();
+ Foo(const Foo&);
+ Foo& operator = (const Foo&);
+ ~Foo();
+ };
+} // anonymous namespace
+static Union<int, Foo> u;
+
+static_assert(u.index<int>() == 0, "int");
+static_assert(u.index<Foo>() == 1, "Foo");
+static_assert(u.index<char>() == size_t(-1), "char");
+} // namespace sexpr
+} // namespace tmwa
diff --git a/src/sexpr/union.hpp b/src/sexpr/union.hpp
new file mode 100644
index 0000000..e0c3051
--- /dev/null
+++ b/src/sexpr/union.hpp
@@ -0,0 +1,108 @@
+#ifndef TMWA_SEXPR_UNION_HPP
+#define TMWA_SEXPR_UNION_HPP
+// union.hpp - A (unsafe!) convenience wrapper for classes in unions.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# include <utility>
+# include <type_traits>
+# include <cstddef>
+# include <new>
+
+# include "fwd.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+ template<class... T>
+ class Union;
+
+ template<>
+ class Union<>
+ {
+ public:
+ template<class T>
+ constexpr static size_t index()
+ {
+ return -1;
+ }
+ Union() = default;
+ ~Union() = default;
+ Union(const Union&) = delete;
+ Union& operator = (const Union&) = delete;
+ };
+
+ template<class F, class... R>
+ class Union<F, R...>
+ {
+ static_assert(!std::is_const<F>::value, "union elements are not const");
+ static_assert(!std::is_volatile<F>::value, "union elements are not volatile");
+ static_assert(!std::is_reference<F>::value, "union elements are not references");
+ static_assert(Union<R...>::template index<F>() == size_t(-1), "unions do not contain duplicates");
+ union Impl
+ {
+ F first;
+ Union<R...> rest;
+
+ Impl() {}
+ ~Impl() {}
+ } data;
+ public:
+ template<class T>
+ constexpr static size_t index()
+ {
+ return std::is_same<F, T>::value
+ ? 0
+ : 1 + Union<R...>::template index<T>()
+ ?: -1;
+ }
+ template<class T>
+ void get(T*& p) { data.rest.get(p); }
+ void get(F*& p) { p = std::addressof(data.first); }
+ template<class T>
+ void get(const T*& p) const { data.rest.get(p); }
+ void get(const F*& p) const { p = std::addressof(data.first); }
+
+ template<class T>
+ T *get() { T *out; get(out); return out; }
+ template<class T>
+ const T *get() const { const T *out; get(out); return out; }
+
+ Union() = default;
+ ~Union() = default;
+ Union(const Union&) = delete;
+ Union& operator = (const Union&) = delete;
+
+ template<class T, class... A>
+ void construct(A&&... a)
+ {
+ new (get<T>()) T(std::forward<A>(a)...);
+ }
+
+ template<class T>
+ void destruct()
+ {
+ get<T>()->~T();
+ }
+ };
+} // namespace sexpr
+} // namespace tmwa
+
+#endif //TMWA_SEXPR_UNION_HPP
diff --git a/src/sexpr/variant.cpp b/src/sexpr/variant.cpp
new file mode 100644
index 0000000..b1f500a
--- /dev/null
+++ b/src/sexpr/variant.cpp
@@ -0,0 +1,40 @@
+#include "variant.hpp"
+// variant.cpp - Just include the header file.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+namespace
+{
+ struct Foo
+ {
+ Foo() {}
+ ~Foo() {}
+ Foo(Foo&&) {}
+ Foo& operator = (Foo&&) { return *this; }
+ };
+} // anonymous namespace
+ static Variant<int, Foo> v;
+} // namespace sexpr
+} // namespace tmwa
diff --git a/src/sexpr/variant.hpp b/src/sexpr/variant.hpp
new file mode 100644
index 0000000..ccbfeaa
--- /dev/null
+++ b/src/sexpr/variant.hpp
@@ -0,0 +1,119 @@
+#ifndef TMWA_SEXPR_VARIANT_HPP
+#define TMWA_SEXPR_VARIANT_HPP
+// variant.hpp - A single value, multiple type container. Better than boost's.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# include <type_traits>
+# include <cstdint>
+# include <cstddef>
+# include <utility>
+
+# include "union.hpp"
+# include "void.hpp"
+
+# include "fwd.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+# define JOIN(a, b) a##b
+
+# define WITH_VAR(ty, var, expr) \
+ for (bool JOIN(var, _guard) = true; JOIN(var, _guard); ) \
+ for (ty var = expr; JOIN(var, _guard); JOIN(var, _guard) = false)
+# define MATCH(expr) \
+ WITH_VAR(auto&&, _match_var, expr) \
+ switch (tmwa::sexpr::VariantFriend::get_state(_match_var))
+# define CASE(ty, var) \
+ break; \
+ case tmwa::sexpr::VariantFriend::get_state_for<ty, decltype(_match_var)>(): \
+ WITH_VAR(ty, var, tmwa::sexpr::VariantFriend::unchecked_get<ty>(_match_var))
+
+ template<class... T>
+ class Variant
+ {
+ static_assert(sizeof...(T), "A variant must not be empty");
+ };
+ template<class D, class... T>
+ class Variant<D, T...>
+ {
+ constexpr static size_t state_count = 1 + sizeof...(T);
+
+ // simplify things immensely
+ friend class VariantFriend;
+
+ typedef Union<D, T...> DataType;
+ DataType data;
+ size_t state;
+
+ void do_destruct();
+ template<class C, class... A>
+ void do_construct(A&&... a);
+ public:
+ Variant();
+ ~Variant();
+
+ void reset();
+ template<class C, class... A>
+ void emplace(A&&... a);
+
+ Variant(const Variant& r);
+ Variant(Variant&& r);
+ Variant& operator = (const Variant& r);
+ Variant& operator = (Variant&& r);
+
+ template<class E>
+ Variant(E e)
+ {
+ do_construct<E, E>(std::move(e));
+ }
+
+ template<class E>
+ Variant& operator = (E e)
+ {
+ emplace<E, E>(std::move(e));
+ return *this;
+ }
+
+ // use these ONLY if only one type makes sense
+ // otherwise use apply
+ template<class E>
+ bool is() const;
+
+ template<class E>
+ E *get_if();
+
+ template<class E>
+ const E *get_if() const;
+ };
+
+ template<class R, class F>
+ void apply(R& r, F&& f);
+ template<class R, class F, class V1, class... V>
+ void apply(R& r, F&& f, V1&& v1, V&&... v);
+ template<class F, class... V>
+ void apply(Void&& r, F&& f, V&&... v);
+} // namespace sexpr
+} // namespace tmwa
+
+# include "variant.tcc"
+
+#endif //TMWA_SEXPR_VARIANT_HPP
diff --git a/src/sexpr/variant.tcc b/src/sexpr/variant.tcc
new file mode 100644
index 0000000..424a8f1
--- /dev/null
+++ b/src/sexpr/variant.tcc
@@ -0,0 +1,293 @@
+// variant.tcc - implementation of inlines and templates in variant.hpp
+//
+// Copyright © 2012-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <cassert>
+#include "bind.hpp"
+
+namespace tmwa
+{
+namespace sexpr
+{
+ class VariantFriend
+ {
+ public:
+ template<class U, class... T, class... A>
+ static void unchecked_do_construct(Variant<T...> *var, A&&... a)
+ {
+ var->template do_construct<U, A...>(std::forward<A>(a)...);
+ }
+ template<class E, class... T>
+ static E& unchecked_get(Variant<T...>& var)
+ {
+ return *var.data.template get<E>();
+ }
+ template<class E, class... T>
+ static const E& unchecked_get(const Variant<T...>& var)
+ {
+ return *var.data.template get<E>();
+ }
+ template<class E, class... T>
+ static E&& unchecked_get(Variant<T...>&& var)
+ {
+ return std::move(*var.data.template get<E>());
+ }
+ template<class E, class... T>
+ static const E&& unchecked_get(const Variant<T...>&& var)
+ {
+ return std::move(*var.data.template get<E>());
+ }
+
+ template<class E, class R, class F, class V1, class... V>
+ static void _apply_unchecked(R& r, F&& f, V1&& v1, V&&... v)
+ {
+ apply(r, bind_variadic(std::forward<F>(f), VariantFriend::unchecked_get<E>(std::forward<V1>(v1))), std::forward<V>(v)...);
+ }
+
+ template<class... T, class R, class F, class V1, class... V>
+ static void _apply_dispatch(const Variant<T...> *, R& r, F&& f, V1&& v1, V&&... v)
+ {
+ typedef void (*Function)(R&, F&&, V1&&, V&&...);
+ constexpr static Function dispatch[sizeof...(T)] = { _apply_unchecked<T, R, F, V1, V...>... };
+ assert(v1.state < sizeof...(T));
+ dispatch[v1.state](r, std::forward<F>(f), std::forward<V1>(v1), std::forward<V>(v)...);
+ }
+
+ template<class... T>
+ static size_t get_state(const Variant<T...>& variant)
+ {
+ return variant.state;
+ }
+
+ template<class W, class V>
+ constexpr static size_t get_state_for()
+ {
+ return std::remove_reference<V>::type::DataType::template index<W>();
+ }
+ };
+
+
+ struct Destruct
+ {
+ template<class U>
+ void operator ()(U& v)
+ {
+ v.~U();
+ }
+ };
+
+ template<class D, class... T>
+ void Variant<D, T...>::do_destruct()
+ {
+ apply(Void(), Destruct(), *this);
+ }
+
+ template<class D, class... T>
+ template<class C, class... A>
+ void Variant<D, T...>::do_construct(A&&... a)
+ {
+ try
+ {
+ data.template construct<C, A...>(std::forward<A>(a)...);
+ state = Union<D, T...>::template index<C>();
+ }
+ catch(...)
+ {
+ static_assert(std::is_nothrow_constructible<D>::value, "first element is nothrow constructible");
+ data.template construct<D>();
+ state = 0;
+ throw;
+ }
+ }
+
+ template<class D, class... T>
+ Variant<D, T...>::Variant()
+ {
+ do_construct<D>();
+ state = 0;
+ }
+
+ template<class D, class... T>
+ Variant<D, T...>::~Variant()
+ {
+ do_destruct();
+ }
+
+ template<class D, class... T>
+ void Variant<D, T...>::reset()
+ {
+ do_destruct();
+ do_construct<D>();
+ }
+
+ template<class D, class... T>
+ template<class C, class... A>
+ void Variant<D, T...>::emplace(A&&... a)
+ {
+ do_destruct();
+ do_construct<C, A...>(std::forward<A>(a)...);
+ }
+
+ template<class... T>
+ class CopyConstruct
+ {
+ Variant<T...> *target;
+ public:
+ CopyConstruct(Variant<T...> *v) : target(v) {}
+ template<class U>
+ void operator ()(const U& u)
+ {
+ VariantFriend::unchecked_do_construct<U>(target, u);
+ }
+ };
+ template<class... T>
+ class MoveConstruct
+ {
+ Variant<T...> *target;
+ public:
+ MoveConstruct(Variant<T...> *v) : target(v) {}
+ template<class U>
+ void operator ()(U&& u)
+ {
+ VariantFriend::unchecked_do_construct<U>(target, std::move(u));
+ }
+ };
+
+ // assignment requires unchecked access
+ template<class... T>
+ class CopyAssign
+ {
+ Union<T...> *data;
+ public:
+ CopyAssign(Union<T...> *d) : data(d) {}
+ template<class U>
+ void operator ()(const U& u)
+ {
+ *data->template get<U>() = u;
+ }
+ };
+
+ template<class... T>
+ class MoveAssign
+ {
+ Union<T...> *data;
+ public:
+ MoveAssign(Union<T...> *d) : data(d) {}
+ template<class U>
+ void operator () (U&& u)
+ {
+ *data->template get<U>() = std::move(u);
+ }
+ };
+
+ template<class D, class... T>
+ Variant<D, T...>::Variant(const Variant& r)
+ {
+ apply(Void(), CopyConstruct<D, T...>(this), r);
+ }
+
+ template<class D, class... T>
+ Variant<D, T...>::Variant(Variant&& r)
+ {
+ apply(Void(), MoveConstruct<D, T...>(this), std::move(r));
+ }
+
+ template<class D, class... T>
+ Variant<D, T...>& Variant<D, T...>::operator = (const Variant& r)
+ {
+ if (state == r.state)
+ apply(Void(), CopyAssign<D, T...>(this), r);
+ else
+ {
+ do_destruct();
+ apply(Void(), CopyConstruct<D, T...>(this), r);
+ }
+ return *this;
+ }
+
+ template<class D, class... T>
+ Variant<D, T...>& Variant<D, T...>::operator = (Variant&& r)
+ {
+ if (state == r.state)
+ apply(Void(), MoveAssign<D, T...>(&data), std::move(r));
+ else
+ {
+ do_destruct();
+ apply(Void(), MoveConstruct<D, T...>(this), std::move(r));
+ }
+ return *this;
+ }
+
+ template<class D, class... T>
+ template<class E>
+ bool Variant<D, T...>::is() const
+ {
+ return get_if<E>();
+ }
+
+ template<class D, class... T>
+ template<class E>
+ E *Variant<D, T...>::get_if()
+ {
+ if (state == Union<D, T...>::template index<E>())
+ return data.template get<E>();
+ return nullptr;
+ }
+
+ template<class D, class... T>
+ template<class E>
+ const E *Variant<D, T...>::get_if() const
+ {
+ if (state == Union<D, T...>::template index<E>())
+ return data.template get<E>();
+ return nullptr;
+ }
+
+ template<class R, class F>
+ void _apply_assign(std::true_type, R& r, F&& f)
+ {
+ std::forward<F>(f)();
+ r = Void();
+ }
+
+ template<class R, class F>
+ void _apply_assign(std::false_type, R& r, F&& f)
+ {
+ r = std::forward<F>(f)();
+ }
+
+ template<class R, class F>
+ void apply(R& r, F&& f)
+ {
+ _apply_assign(std::is_void<decltype(std::forward<F>(f)())>(), r, std::forward<F>(f));
+ }
+
+ template<class R, class F, class V1, class... V>
+ void apply(R& r, F&& f, V1&& v1, V&&... v)
+ {
+ VariantFriend::_apply_dispatch(&v1, r, std::forward<F>(f), std::forward<V1>(v1), std::forward<V>(v)...);
+ }
+
+ template<class F, class... V>
+ void apply(Void&& r, F&& f, V&&... v)
+ {
+ apply(r, std::forward<F>(f), std::forward<V>(v)...);
+ }
+
+} // namespace sexpr
+} // namespace tmwa
diff --git a/src/sexpr/variant_test.cpp b/src/sexpr/variant_test.cpp
new file mode 100644
index 0000000..1ecb82f
--- /dev/null
+++ b/src/sexpr/variant_test.cpp
@@ -0,0 +1,125 @@
+#include "variant.hpp"
+// variant_test.cpp - Testsuite for multi-type container that's better than boost's.
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include <gtest/gtest.h>
+
+#include "../strings/vstring.hpp"
+
+//#include "../poison.hpp"
+
+
+namespace tmwa
+{
+#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
+
+ struct Tracker
+ {
+ int id, moves, copies;
+
+ explicit
+ Tracker(int i)
+ : id(i), moves(0), copies(0)
+ {}
+ Tracker(Tracker&& rhs)
+ : id(rhs.id), moves(rhs.moves + 1), copies(rhs.copies)
+ { rhs.id = 0; }
+ Tracker(const Tracker& rhs)
+ : id(rhs.id), moves(rhs.moves), copies(rhs.copies + 1)
+ {}
+ Tracker& operator = (Tracker&& rhs)
+ { id = rhs.id; moves = rhs.moves + 1; copies = rhs.copies; rhs.id = 0; return *this; }
+ Tracker& operator = (const Tracker& rhs)
+ { id = rhs.id; moves = rhs.moves; copies = rhs.copies + 1; return *this; }
+ };
+ struct Foo : Tracker
+ {
+ // needed for first param of variant
+ Foo() noexcept : Tracker(0) { abort(); }
+
+ Foo(int i) : Tracker(i) {}
+ };
+ struct Bar : Tracker
+ {
+ Bar(int i) : Tracker(i) {}
+ };
+ struct Qux : Tracker
+ {
+ // needed for first param of variant
+ Qux() noexcept : Tracker(0) { abort(); }
+
+ Qux(int i) : Tracker(i) {}
+ Qux(Qux&&) = default;
+ Qux(const Qux&) = delete;
+ Qux& operator = (Qux&&) = default;
+ Qux& operator = (const Qux&) = default;
+ };
+
+TEST(variant, match)
+{
+ struct Sub : sexpr::Variant<Foo, Bar>
+ {
+ Sub()
+ : sexpr::Variant<Foo, Bar>(Foo(1))
+ {}
+ };
+ Sub v1;
+ MATCH (v1)
+ {
+ // This is not a public API, it's just for testing.
+ default:
+ FAIL();
+
+ CASE(Foo, f)
+ {
+ (void)f;
+ SUCCEED();
+ }
+ CASE(Bar, b)
+ {
+ (void)b;
+ FAIL();
+ }
+ }
+ v1.emplace<Bar>(2);
+ MATCH (v1)
+ {
+ // This is not a public API, it's just for testing.
+ default:
+ FAIL();
+
+ CASE(Foo, f)
+ {
+ (void)f;
+ FAIL();
+ }
+ CASE(Bar, b)
+ {
+ (void)b;
+ SUCCEED();
+ }
+ }
+}
+
+TEST(variant, copymove)
+{
+ sexpr::Variant<Qux> moveonly(Qux(3));
+ (void)moveonly;
+}
+} // namespace tmwa
diff --git a/src/sexpr/void.cpp b/src/sexpr/void.cpp
new file mode 100644
index 0000000..9f0eeb5
--- /dev/null
+++ b/src/sexpr/void.cpp
@@ -0,0 +1,29 @@
+#include "void.hpp"
+// void.cpp - Just include the header file.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+} // namespace sexpr
+} // namespace tmwa
diff --git a/src/sexpr/void.hpp b/src/sexpr/void.hpp
new file mode 100644
index 0000000..9fb6bc4
--- /dev/null
+++ b/src/sexpr/void.hpp
@@ -0,0 +1,43 @@
+#ifndef TMWA_SEXPR_VOID_HPP
+#define TMWA_SEXPR_VOID_HPP
+// void.hpp - A type that represents nothing and anything.
+//
+// Copyright © 2012 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# include "fwd.hpp"
+
+
+namespace tmwa
+{
+namespace sexpr
+{
+ struct Void
+ {
+ template<class T>
+ constexpr operator T() noexcept { return T(); }
+ template<class T>
+ void operator = (T&&) noexcept {}
+ template<class T>
+ constexpr Void(T&&) noexcept {}
+ constexpr Void() noexcept;
+ };
+ constexpr Void::Void() noexcept = default;
+} // namespace sexpr
+} // namespace tmwa
+
+#endif //TMWA_SEXPR_VOID_HPP