2016-01-28 15:19:09 +01:00
|
|
|
|
/*
|
|
|
|
|
|
TUPLE-RECORD-INIT.hpp - adapter to construct tuple components from GenNode entries
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2016, Hermann Vosseler <Ichthyostega@web.de>
|
2016-01-28 15:19:09 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2016-01-28 15:19:09 +01:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @file tuple-record-init.hpp
|
|
|
|
|
|
** Specialised adapter to consume a record of GenNode entries to build a tuple.
|
|
|
|
|
|
** This is a complement to lib::meta::TupleConstructor to deal with arguments
|
|
|
|
|
|
** passed in our "External Tree Description" form. This is relevant for structural
|
|
|
|
|
|
** diff and the invocation of actions driven by messages via the UI-Bus.
|
|
|
|
|
|
**
|
2017-04-09 01:34:18 +02:00
|
|
|
|
** In those cases, a sequence of arguments will be passed within a run-time sequential
|
2016-01-28 15:19:09 +01:00
|
|
|
|
** container, as a sequence of GenNode entries. The latter are variant records,
|
|
|
|
|
|
** which means they can hold any of a small collection of basic types, like
|
|
|
|
|
|
** numbers, strings, time values etc. So we have to face two challenges here.
|
|
|
|
|
|
** - the sequence of types in a std::tuple is fixed at compile time, as is
|
|
|
|
|
|
** the sequence of constructor arguments to build a given tuple type.
|
|
|
|
|
|
** Thus we need a compile-time iteration over a run-time sequence container
|
|
|
|
|
|
** - the concrete type of the given initialisation value is opaque, hidden within
|
|
|
|
|
|
** the GenNode variant record. And especially this means that the concrete type
|
|
|
|
|
|
** is known only at runtime. But we need to generate the construction code at
|
|
|
|
|
|
** compile time. The remedy here is to use double dispatch, i.e. to build a
|
|
|
|
|
|
** trampoline table with all the basically possible conversion paths for one
|
|
|
|
|
|
** specific type within the target tuple. For example, if one component of our
|
|
|
|
|
|
** tuple is a `long`, we'll provide a conversion path for the case when the
|
|
|
|
|
|
** GenNode holds a `short`, an `int`, and -- depending on the platform -- when
|
|
|
|
|
|
** it holds a `int64_t` (please recall that long and int are the same type on
|
|
|
|
|
|
** 32bit platforms!). When encountering any other of the possible types within
|
|
|
|
|
|
** GenNode (e.g. `string` or `TimeSpan`), a type mismatch exception is raised.
|
|
|
|
|
|
**
|
|
|
|
|
|
** @see control::CommandDef usage example
|
|
|
|
|
|
** @see TupleHelper_test
|
|
|
|
|
|
** @see typelist.hpp
|
|
|
|
|
|
** @see function.hpp
|
|
|
|
|
|
** @see generator.hpp
|
|
|
|
|
|
**
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_META_TUPLE_RECORD_INIT_H
|
|
|
|
|
|
#define LIB_META_TUPLE_RECORD_INIT_H
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/meta/tuple-helper.hpp"
|
|
|
|
|
|
#include "lib/meta/typelist-manip.hpp"
|
|
|
|
|
|
#include "lib/meta/typeseq-util.hpp"
|
|
|
|
|
|
#include "lib/meta/generator.hpp"
|
|
|
|
|
|
#include "lib/diff/gen-node.hpp"
|
|
|
|
|
|
#include "lib/meta/trait.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade: address warnings -- shaddowing overloaded-virtual
This is an advanced diagnostics added (presumably) with GCC-13
and attempts to protect against an insidious side-effect of ''overload resolution''
Basically C++ (like its ancestor C) is oriented towards direct linkage and adds
the OO-style dynamic dispatch (through virtual functions and a VTable)
only as an extension, which must be requested explicitly.
Thus the resolution of ''overloads'' (as opposed to ''overridden'' virtual functions)
always takes precedence and happens within the directly visible scope,
which can cause the compiler to perform an implicit conversion instead of
invoking a different virtual function, which is defined in a base class.
However, this diagnostics seems to be implemented in an overly zealous way:
The compiler warns at the time of the type instantiation, and even in cases
where it is effectively impossible to encounter this dangerous shadowing situation.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109740
This leads to several ill-guided warnings in the Lumiera code base, which unfortunately
can only be addressed by disabling this diagnostics for all usages of some header.
The reason is, we often generate chains of template instantiations driven by type lists,
and in such usage pattern, it is not even possible to bring all the other inherited overloads
into scope (with a using `BASE::func` clause), because such a specification would be ambiguous
and result in a real compile error, because even the interface is generated from a chain of mix-in templates
2025-04-15 22:42:34 +02:00
|
|
|
|
// GCC > 13 warns at class definition when a new overload shadows an inherited virtual function.
|
|
|
|
|
|
// While theoretically correct, in practice any call will be dispatched through the base interface,
|
|
|
|
|
|
// which in turn is also generated by metaprogramming from a type list.
|
|
|
|
|
|
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109740
|
|
|
|
|
|
_Pragma("GCC diagnostic push") \
|
|
|
|
|
|
_Pragma("GCC diagnostic ignored \"-Woverloaded-virtual\"")
|
|
|
|
|
|
|
2016-01-28 15:19:09 +01:00
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace meta {
|
2016-02-08 23:29:15 +01:00
|
|
|
|
namespace error = lumiera::error;
|
2016-01-28 15:19:09 +01:00
|
|
|
|
|
|
|
|
|
|
namespace { // implementation details...
|
|
|
|
|
|
|
|
|
|
|
|
using lib::Variant;
|
|
|
|
|
|
using lib::diff::Rec;
|
|
|
|
|
|
using lib::diff::GenNode;
|
|
|
|
|
|
using lib::diff::DataValues;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** the visitor type our converter is based on */
|
|
|
|
|
|
using DataCapPredicate = Variant<DataValues>::Predicate;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @internal
|
|
|
|
|
|
* specialised Accessor to retrieve a given target type
|
|
|
|
|
|
* from a run-time typed, opaque GenNode element. Since GenNode
|
|
|
|
|
|
* may hold some value from a (\ref lib::diff::DataValues small
|
|
|
|
|
|
* and fixed selection of types), we prepare a converter function
|
|
|
|
|
|
* for each sensible conversion path to the given `TAR` target type.
|
|
|
|
|
|
* This converter will placement-construct a target value in a buffer
|
2016-12-23 07:26:00 +01:00
|
|
|
|
* reserved within this Accessor object.
|
2016-01-28 15:19:09 +01:00
|
|
|
|
* @warning template bloat: we get a converter for each possible conversion
|
|
|
|
|
|
* for each instantiation of this template, irrespective if we actually
|
|
|
|
|
|
* need it or not. The price is payed per distinct type used within some
|
|
|
|
|
|
* target tuple; we get a VTable and some conversion functions for each.
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename TAR>
|
|
|
|
|
|
struct GenNodeAccessor
|
2018-03-24 05:35:13 +01:00
|
|
|
|
: util::NonCopyable
|
2016-01-28 15:19:09 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
template<typename TY>
|
|
|
|
|
|
struct allow_Conversion
|
|
|
|
|
|
: __and_<is_constructible<TAR, TY const&>
|
|
|
|
|
|
,__not_<is_narrowingInit<typename Strip<TY>::TypePlain
|
|
|
|
|
|
,typename Strip<TAR>::TypePlain>>
|
|
|
|
|
|
>
|
|
|
|
|
|
{ };
|
|
|
|
|
|
|
|
|
|
|
|
using SupportedSourceTypes = typename Filter<DataValues::List, allow_Conversion>::List;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct ConverterBase
|
|
|
|
|
|
: DataCapPredicate
|
|
|
|
|
|
{
|
|
|
|
|
|
char buffer[sizeof(TAR)];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<typename TY, class BA>
|
|
|
|
|
|
class Converter
|
|
|
|
|
|
: public BA
|
|
|
|
|
|
{
|
|
|
|
|
|
virtual bool
|
|
|
|
|
|
handle(TY const& srcElm)
|
|
|
|
|
|
{
|
|
|
|
|
|
new(&(BA::buffer)) TAR{srcElm};
|
|
|
|
|
|
return true;
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using ConversionBuffer = InstantiateChained< SupportedSourceTypes // for each of those types...
|
|
|
|
|
|
, Converter // instantiate the Converter template
|
|
|
|
|
|
, ConverterBase // and use this as common base class.
|
|
|
|
|
|
>; // RESULT: for each type we get a handle(TY)
|
|
|
|
|
|
|
|
|
|
|
|
ConversionBuffer converter_;
|
|
|
|
|
|
|
|
|
|
|
|
TAR&
|
|
|
|
|
|
accessTargetElement()
|
|
|
|
|
|
{
|
|
|
|
|
|
return *reinterpret_cast<TAR*> (&converter_.buffer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
GenNodeAccessor (GenNode const& node)
|
|
|
|
|
|
: converter_()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (not node.data.accept (converter_))
|
|
|
|
|
|
throw error::Invalid ("Unable to build «" + util::typeStr<TAR>()
|
|
|
|
|
|
+"» element from " + string(node)
|
|
|
|
|
|
,error::LUMIERA_ERROR_WRONG_TYPE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @note RAII: when the ctor succeeds, we know the target element was built */
|
|
|
|
|
|
~GenNodeAccessor()
|
|
|
|
|
|
{
|
|
|
|
|
|
accessTargetElement().~TAR();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
operator TAR ()
|
|
|
|
|
|
{
|
|
|
|
|
|
return accessTargetElement();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
Upgrade: address warnings -- shaddowing overloaded-virtual
This is an advanced diagnostics added (presumably) with GCC-13
and attempts to protect against an insidious side-effect of ''overload resolution''
Basically C++ (like its ancestor C) is oriented towards direct linkage and adds
the OO-style dynamic dispatch (through virtual functions and a VTable)
only as an extension, which must be requested explicitly.
Thus the resolution of ''overloads'' (as opposed to ''overridden'' virtual functions)
always takes precedence and happens within the directly visible scope,
which can cause the compiler to perform an implicit conversion instead of
invoking a different virtual function, which is defined in a base class.
However, this diagnostics seems to be implemented in an overly zealous way:
The compiler warns at the time of the type instantiation, and even in cases
where it is effectively impossible to encounter this dangerous shadowing situation.
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109740
This leads to several ill-guided warnings in the Lumiera code base, which unfortunately
can only be addressed by disabling this diagnostics for all usages of some header.
The reason is, we often generate chains of template instantiations driven by type lists,
and in such usage pattern, it is not even possible to bring all the other inherited overloads
into scope (with a using `BASE::func` clause), because such a specification would be ambiguous
and result in a real compile error, because even the interface is generated from a chain of mix-in templates
2025-04-15 22:42:34 +02:00
|
|
|
|
|
2016-01-28 15:19:09 +01:00
|
|
|
|
}//(End)implementation details
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Concrete specialisation to build a std::tuple from a sequence
|
|
|
|
|
|
* of GenNode elements, with run-time type compatibility check.
|
|
|
|
|
|
* @remarks intention is to use this within (\ref TupleConstructor),
|
|
|
|
|
|
* as will happen automatically when invoking (\ref buildTuple() )
|
|
|
|
|
|
* with a `Record<GenNode>` as argument. The embedded template
|
|
|
|
|
|
* `Access<i>` will be initialised with (a reference) to the
|
|
|
|
|
|
* source record, followed by an attempt to convert it to the
|
|
|
|
|
|
* individual member type at position i within the target tuple.
|
|
|
|
|
|
* @throws error::Invalid when the number of types within the target
|
|
|
|
|
|
* exceeds the number of children within the source record.
|
|
|
|
|
|
* \ref LUMIERA_ERROR_INDEX_BOUNDS
|
|
|
|
|
|
* @throws error::Invalid when some source GenNode element
|
|
|
|
|
|
* can not be sensibly converted to the corresponding
|
|
|
|
|
|
* type in the target tuple.
|
|
|
|
|
|
* \ref LUMIERA_ERROR_WRONG_TYPE
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename...TYPES>
|
|
|
|
|
|
struct ElementExtractor<lib::diff::Rec, std::tuple<TYPES...>>
|
|
|
|
|
|
{
|
|
|
|
|
|
template<size_t i>
|
2025-06-07 18:04:59 +02:00
|
|
|
|
using TargetType = typename Pick<Types<TYPES...>, i>::Type;
|
2016-01-28 15:19:09 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<size_t i>
|
|
|
|
|
|
struct Access
|
|
|
|
|
|
{
|
|
|
|
|
|
Rec const& values;
|
|
|
|
|
|
|
|
|
|
|
|
operator TargetType<i> ()
|
|
|
|
|
|
{
|
2016-02-08 23:29:15 +01:00
|
|
|
|
using util::toString;
|
|
|
|
|
|
|
|
|
|
|
|
if (values.childSize() <= i)
|
|
|
|
|
|
throw error::Logic ("Attempt to init the " + toString(sizeof...(TYPES))
|
|
|
|
|
|
+" element " + util::typeStr<std::tuple<TYPES...>>()
|
|
|
|
|
|
+" from an Rec<GenNode> with only " + toString(values.childSize())
|
|
|
|
|
|
+" child elements: " + toString(values)
|
|
|
|
|
|
,error::LUMIERA_ERROR_WRONG_TYPE);
|
|
|
|
|
|
|
2016-01-28 15:19:09 +01:00
|
|
|
|
return GenNodeAccessor<TargetType<i>> (values.child(i));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::meta
|
|
|
|
|
|
#endif /*LIB_META_TUPLE_RECORD_INIT_H*/
|