/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2018 Danny Robson */ #pragma once #include "../std.hpp" #include "../types.hpp" #include "../debug.hpp" #include #include #include #include namespace cruft::types { //------------------------------------------------------------------------- enum class category { NONE, UNSIGNED, SIGNED, REAL, }; //------------------------------------------------------------------------- struct description { /// The signed, realness, or voidness of the type. enum category category; /// The number of bytes for an individual instance of this type. std::size_t width; }; constexpr bool operator== (description const &a, description const &b) noexcept { return a.category == b.category && a.width == b.width; } //------------------------------------------------------------------------- template struct category_traits; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template <> struct category_traits : public std::integral_constant {}; template constexpr auto category_traits_v = category_traits::value; //------------------------------------------------------------------------- template constexpr description make_description (void) noexcept { if constexpr (std::is_void_v) { return { .category = category::NONE, .width = 0, }; } else { return { .category = category_traits_v, .width = sizeof (T) }; } } /// Call a functor with the supplied arguments and a type_tag for the /// described native type. /// /// If the type does not exist then throw and invalid_argument exception. template decltype(auto) visit (description const &descriminator, FunctionT &&func, Args&&...args) { switch (descriminator.category) { case category ::NONE: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case category::REAL: switch (descriminator.width) { case 4: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 8: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); default: throw std::invalid_argument ("Unsupported floating point width"); } case category::SIGNED: switch (descriminator.width) { case 1: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 2: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 4: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 8: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); default: throw std::invalid_argument ("Unsupported unsigned width"); } case category::UNSIGNED: switch (descriminator.width) { case 1: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 2: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 4: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); case 8: return std::invoke ( std::forward (func), std::forward (args)..., type_tag {} ); } } unhandled (descriminator.category); } } #include namespace cruft::types { std::ostream& operator<< (std::ostream&, category); std::ostream& operator<< (std::ostream&, description); }