dsdlc: union tag enumeration; improved is()/as()/to() with support for either direct access via StorageType, or indirect access via Spec type

This commit is contained in:
Pavel Kirienko
2015-07-11 07:34:23 +03:00
parent 4000712ae5
commit 38897225d6
@@ -59,6 +59,16 @@ struct UAVCAN_EXPORT ${t.cpp_type_name}
${expand_attr_types(group_name='FieldTypes', attrs=fields)}
% if union:
struct Tag
{
enum Type
{
% for idx,a in enumerate(fields):
${a.name}${',' if idx < (len(fields) - 1) else ''}
% endfor
};
};
typedef IntegerSpec< ::uavcan::IntegerBitLen< ${len(fields)} >::Result,
::uavcan::SignednessUnsigned, ::uavcan::CastModeTruncate > TagType;
@@ -150,12 +160,49 @@ public:
::uavcan::TailArrayOptimizationMode tao_mode = ::uavcan::TailArrayOptEnabled);
% if union:
/**
* Constructors and assignment operators will only work if T is unique within the union; otherwise
* compilation will fail with an error referring to ambiguous template instantiation.
*/
template <typename T>
${type_name}(const T& x)
% for idx,a in enumerate(fields):
${':' if idx == 0 else ','} ${a.name}()
% endfor
% if union:
, _tag_()
% endif
{
to<T>() = x;
}
template <typename T>
${type_name}& operator=(const T& x)
{
to<T>() = x;
return *this;
}
/**
* Use explicit tag access if the union contains non-unique types.
* Otherwise it is safer to use as<>(), to<>(), is<>().
*/
typename Tag::Type getTag() const { return Tag::Type(_tag_); }
void setTag(typename Tag::Type x) { _tag_ = ::uavcan::StorageType< TagType >::Type(x); }
/**
* Whether the union is set to the given type.
* Access by type; this will only work if the type is unique within the union; otherwise compilation will fail.
*/
template <typename T>
bool is() const;
/**
* Whether the union is set to the given type.
* Access by tag; this will work even if there are non-unique types within the union.
*/
bool is(typename Tag::Type x) const { return Tag::Type(_tag_) == x; }
/**
* If the union is currently set to the type T, returns pointer to the appropriate field.
* If the union is set to another type, returns null pointer.
@@ -328,32 +375,49 @@ ${generate_codec_calls_per_field(call_name='encode', self_parameter_type='Parame
${generate_codec_calls_per_field(call_name='decode', self_parameter_type='ReferenceType')}
% if union:
template <>
template <typename T>
typename ::uavcan::EnableIfType< typename T::StorageType, bool>::Type ${scope_prefix}<0>::is() const
{
return is<typename T::StorageType>();
}
template <>
template <typename T>
typename ::uavcan::EnableIfType< typename T::StorageType, const typename T::StorageType*>::Type
${scope_prefix}<0>::as() const
{
return as<typename T::StorageType>();
}
template <>
template <typename T>
typename ::uavcan::EnableIfType< typename T::StorageType, typename T::StorageType&>::Type
${scope_prefix}<0>::to()
{
return to<typename T::StorageType>();
}
% for idx,a in enumerate(fields):
template <>
template <>
bool ${scope_prefix}<0>::is< typename ${scope_prefix}<0>::FieldTypes::${a.name} >() const
bool ${scope_prefix}<0>::is< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >() const
{
return _tag_ == ${idx};
}
% endfor
% for idx,a in enumerate(fields):
template <>
template <>
const typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type*
${scope_prefix}<0>::as< typename ${scope_prefix}<0>::FieldTypes::${a.name} >() const
${scope_prefix}<0>::as< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >() const
{
return is< typename FieldTypes::${a.name} >() ? &${a.name} : NULL;
return is< typename ${scope_prefix}<0>::FieldTypes::${a.name} >() ? &${a.name} : NULL;
}
% endfor
% for idx,a in enumerate(fields):
template <>
template <>
typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type&
${scope_prefix}<0>::to< ${scope_prefix}<0>::FieldTypes::${a.name} >()
${scope_prefix}<0>::to< typename ::uavcan::StorageType< typename ${scope_prefix}<0>::FieldTypes::${a.name} >::Type >()
{
if (_tag_ != ${idx})
{
@@ -368,8 +432,10 @@ ${scope_prefix}<0>::to< ${scope_prefix}<0>::FieldTypes::${a.name} >()
<!--(end)-->
% if t.kind == t.KIND_SERVICE:
${define_out_of_line_struct_methods(scope_prefix=t.cpp_type_name + '::Request_', fields=t.request_fields, union=t.request_union)}
${define_out_of_line_struct_methods(scope_prefix=t.cpp_type_name + '::Response_', fields=t.response_fields, union=t.response_union)}
${define_out_of_line_struct_methods(scope_prefix=t.cpp_type_name + '::Request_', fields=t.request_fields, \
union=t.request_union)}
${define_out_of_line_struct_methods(scope_prefix=t.cpp_type_name + '::Response_', fields=t.response_fields, \
union=t.response_union)}
% else:
${define_out_of_line_struct_methods(scope_prefix=t.cpp_type_name, fields=t.fields, union=t.union)}
% endif