libcruft-util/types/dispatch.hpp

90 lines
3.1 KiB
C++
Raw Normal View History

/*
* 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 <danny@nerdcruft.net>
*/
#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 <typename FunctionT, typename ...Args>
decltype(auto)
visit (description const &descriminator, FunctionT &&func, Args&&...args)
{
#define INVOKE(KLASS) \
return std::invoke( \
std::forward<FunctionT> (func), \
std::forward<Args> (args)..., \
type_tag<KLASS> {} \
);
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<i08>)
case 2: INVOKE(unknown_enum_tag<i16>)
case 3: INVOKE(unknown_enum_tag<i32>)
case 4: INVOKE(unknown_enum_tag<i64>)
}
} else {
switch (descriminator.width) {
case 1: INVOKE(unknown_enum_tag<u08>)
case 2: INVOKE(unknown_enum_tag<u16>)
case 3: INVOKE(unknown_enum_tag<u32>)
case 4: INVOKE(unknown_enum_tag<u64>)
}
}
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
}
}