/* * 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-2019 Danny Robson */ #pragma once #include "description.hpp" #include "../types.hpp" namespace cruft::types { /// 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. /// /// We split the calls into two here so that there's no possibility of /// recursion (which will blow up the compiler) when we handle the /// dispatch of enums. template decltype(auto) visit (description const &descriminator, FunctionT &&func, Args&&...args) { #define INVOKE(TAG) \ return std::invoke( \ std::forward (func), \ std::forward (args)..., \ TAG \ ); switch (descriminator.category) { case category ::NONE: INVOKE(type_tag {}) case category::REAL: switch (descriminator.width) { case 4: INVOKE(type_tag {}) case 8: INVOKE(type_tag {}) default: throw std::invalid_argument ("Unsupported floating point width"); } case category::BOOL: INVOKE(type_tag {}) case category::ENUM: { if (descriminator.signedness) { switch (descriminator.width) { case 1: INVOKE(type_tag> { descriminator }) case 2: INVOKE(type_tag> { descriminator }) case 4: INVOKE(type_tag> { descriminator }) case 8: INVOKE(type_tag> { descriminator }) } } else { switch (descriminator.width) { case 1: INVOKE(type_tag> { descriminator }) case 2: INVOKE(type_tag> { descriminator }) case 4: INVOKE(type_tag> { descriminator }) case 8: INVOKE(type_tag> { descriminator }) } } break; } case category::INTEGER: CHECK_EQ (category::INTEGER, descriminator.category); if (descriminator.signedness) { switch (descriminator.width) { case 1: INVOKE(type_tag {}) case 2: INVOKE(type_tag {}) case 4: INVOKE(type_tag {}) case 8: INVOKE(type_tag {}) } } else { switch (descriminator.width) { case 1: INVOKE(type_tag {}) case 2: INVOKE(type_tag {}) case 4: INVOKE(type_tag {}) case 8: INVOKE(type_tag {}) } } unhandled (descriminator.category); } unhandled (descriminator.category); #undef INVOKE } }