92 lines
3.5 KiB
C++
92 lines
3.5 KiB
C++
/*
|
|
* 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>
|
|
*/
|
|
|
|
#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 <typename FunctionT, typename ...Args>
|
|
decltype(auto)
|
|
visit (description const &descriminator, FunctionT &&func, Args&&...args)
|
|
{
|
|
#define INVOKE(TAG) \
|
|
return std::invoke( \
|
|
std::forward<FunctionT> (func), \
|
|
std::forward<Args> (args)..., \
|
|
TAG \
|
|
);
|
|
|
|
switch (descriminator.category) {
|
|
case category ::NONE: INVOKE(type_tag<void> {})
|
|
case category::REAL:
|
|
switch (descriminator.width) {
|
|
case 4: INVOKE(type_tag<f32> {})
|
|
case 8: INVOKE(type_tag<f64> {})
|
|
default:
|
|
throw std::invalid_argument ("Unsupported floating point width");
|
|
}
|
|
|
|
case category::BOOL: INVOKE(type_tag<bool> {})
|
|
|
|
case category::ENUM: {
|
|
if (descriminator.signedness) {
|
|
switch (descriminator.width) {
|
|
case 1: INVOKE(type_tag<unknown_enum_tag<i08>> { descriminator })
|
|
case 2: INVOKE(type_tag<unknown_enum_tag<i16>> { descriminator })
|
|
case 4: INVOKE(type_tag<unknown_enum_tag<i32>> { descriminator })
|
|
case 8: INVOKE(type_tag<unknown_enum_tag<i64>> { descriminator })
|
|
}
|
|
} else {
|
|
switch (descriminator.width) {
|
|
case 1: INVOKE(type_tag<unknown_enum_tag<u08>> { descriminator })
|
|
case 2: INVOKE(type_tag<unknown_enum_tag<u16>> { descriminator })
|
|
case 4: INVOKE(type_tag<unknown_enum_tag<u32>> { descriminator })
|
|
case 8: INVOKE(type_tag<unknown_enum_tag<u64>> { descriminator })
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case category::INTEGER:
|
|
CHECK_EQ (category::INTEGER, descriminator.category);
|
|
|
|
if (descriminator.signedness) {
|
|
switch (descriminator.width) {
|
|
case 1: INVOKE(type_tag<i08> {})
|
|
case 2: INVOKE(type_tag<i16> {})
|
|
case 4: INVOKE(type_tag<i32> {})
|
|
case 8: INVOKE(type_tag<i64> {})
|
|
}
|
|
} else {
|
|
switch (descriminator.width) {
|
|
case 1: INVOKE(type_tag<u08> {})
|
|
case 2: INVOKE(type_tag<u16> {})
|
|
case 4: INVOKE(type_tag<u32> {})
|
|
case 8: INVOKE(type_tag<u64> {})
|
|
}
|
|
}
|
|
|
|
unhandled (descriminator.category);
|
|
}
|
|
|
|
unhandled (descriminator.category);
|
|
#undef INVOKE
|
|
}
|
|
}
|