#pragma once // union.hpp - A (unsafe!) convenience wrapper for classes in unions. // // Copyright © 2012 Ben Longbons // // 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 . #include #include #include #include #include "fwd.hpp" namespace tmwa { namespace sexpr { template class Union; template<> class Union<> { public: template constexpr static size_t index() { return -1; } Union() = default; ~Union() = default; Union(const Union&) = delete; Union& operator = (const Union&) = delete; }; template class Union { static_assert(!std::is_const::value, "union elements are not const"); static_assert(!std::is_volatile::value, "union elements are not volatile"); static_assert(!std::is_reference::value, "union elements are not references"); static_assert(Union::template index() == size_t(-1), "unions do not contain duplicates"); union Impl { F first; Union rest; Impl() {} ~Impl() {} } data; public: template constexpr static size_t index() { return std::is_same::value ? 0 : 1 + Union::template index() ?: -1; } template void get(T*& p) { data.rest.get(p); } void get(F*& p) { p = std::addressof(data.first); } template void get(const T*& p) const { data.rest.get(p); } void get(const F*& p) const { p = std::addressof(data.first); } template T *get() { T *out; get(out); return out; } template 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 void construct(A&&... a) { new (get()) T(std::forward(a)...); } template void destruct() { get()->~T(); } }; } // namespace sexpr } // namespace tmwa