/* * 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 */ #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(KLASS) \ return std::invoke( \ std::forward (func), \ std::forward (args)..., \ type_tag {} \ ); switch (descriminator.category) { case category ::NONE: INVOKE(void) case category::REAL: switch (descriminator.width) { case 4: INVOKE(f32) case 8: INVOKE(f64) default: throw std::invalid_argument ("Unsupported floating point width"); } case category::BOOL: INVOKE(bool) case category::ENUM: { if (descriminator.signedness) { switch (descriminator.width) { case 1: INVOKE(unknown_enum_tag) case 2: INVOKE(unknown_enum_tag) case 3: INVOKE(unknown_enum_tag) case 4: INVOKE(unknown_enum_tag) } } else { switch (descriminator.width) { case 1: INVOKE(unknown_enum_tag) case 2: INVOKE(unknown_enum_tag) case 3: INVOKE(unknown_enum_tag) case 4: INVOKE(unknown_enum_tag) } } break; } case category::INTEGER: CHECK_EQ (category::INTEGER, descriminator.category); if (descriminator.signedness) { switch (descriminator.width) { case 1: INVOKE(i08) case 2: INVOKE(i16) case 3: INVOKE(i32) case 4: INVOKE(i64) } } else { switch (descriminator.width) { case 1: INVOKE(u08) case 2: INVOKE(u16) case 3: INVOKE(u32) case 4: INVOKE(u64) } } unhandled (descriminator.category); } unhandled (descriminator.category); #undef INVOKE } }