Upgrade: switch to C++23 (see #1245)

The Lumiera »Reference Platform« is now upgraded to Debian/Buster, which provides GCC-14 and Clang-20.
Thus the compiler support for C++20 language features seems solid enough, and C++23,
while still in ''experimental stage'' can be seen as a complement and addendum.

This changeset
 * upgrades the compile switches for the build system
 * provides all the necessary adjustments to keep the code base compilable

Notable changes:
 * λ-capture by value now requires explicit qualification how to handle `this`
 * comparison operators are now handled transparently by the core language,
   largely obsoleting boost::operators. This change incurs several changes
   to implicit handling rules and causes lots of ambiguities — which typically
   pinpoint some long standing design issues, especially related to MObjects
   and the ''time entities''. Most tweaks done here can be ''considered preliminary''
 * unfortunately the upgraded standard ''fails'' to handle **tuple-like** entities
   in a satisfactory way — rather an ''exposition-only'' concept is introduced,
   which applies solely to some containers from the STL, thereby breaking some
   very crucial code in the render entities, which was built upon the notion of
   ''tuple-like'' entities and the ''tuple protocol''. The solution is to
   abandon the STL in this respect and **provide an alternative implementation**
   of the `apply` function and related elements.
This commit is contained in:
Fischlurch 2025-06-18 16:50:19 +02:00
parent d888891d84
commit afa7ca2e4d
44 changed files with 1165 additions and 104 deletions

View file

@ -65,7 +65,7 @@ def defineBuildEnvironment():
env.Replace( CPPPATH =["#src"] # used to find includes, "#" means always absolute to build-root env.Replace( CPPPATH =["#src"] # used to find includes, "#" means always absolute to build-root
, CPPDEFINES=['LUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines , CPPDEFINES=['LUMIERA_VERSION='+VERSION ] # note: it's a list to append further defines
, CCFLAGS='-Wall -Wextra -Wformat-security' , CCFLAGS='-Wall -Wextra -Wformat-security'
, CXXFLAGS='-std=gnu++17 -Wno-enum-compare' , CXXFLAGS='-std=gnu++23 -Wno-enum-compare'
, CFLAGS='-std=gnu99' , CFLAGS='-std=gnu99'
) )
env.Append(LINKFLAGS='-Wl,--no-undefined') # require every dependency is given on link, in the right order env.Append(LINKFLAGS='-Wl,--no-undefined') # require every dependency is given on link, in the right order

View file

@ -115,7 +115,7 @@ namespace stage {
facade.reset ( // trigger loading of the GuiStarterPlugin... facade.reset ( // trigger loading of the GuiStarterPlugin...
new GuiRunner ( new GuiRunner (
[=] (string* problemMessage) [=,this] (string* problemMessage)
{ // will be invoked when the UI thread exits { // will be invoked when the UI thread exits
closeGuiModule(); closeGuiModule();
termNotification(problemMessage); termNotification(problemMessage);

View file

@ -121,8 +121,8 @@ namespace lib {
~AllocationCluster () noexcept; ~AllocationCluster () noexcept;
/** hard wired size of storage extents */ /** hard wired size of storage extents */
static size_t constexpr EXTENT_SIZ = 256; static constexpr size_t EXTENT_SIZ = 256;
static size_t constexpr max_size(); static constexpr size_t max_size();
/* === diagnostics === */ /* === diagnostics === */

View file

@ -293,17 +293,17 @@ namespace lib {
template<class FUN> template<class FUN>
explicit explicit
Local (FUN&& buildInstance) Local (FUN&& _buildInstance)
{ {
__assert_compatible<MOC>(); __assert_compatible<MOC>();
__assert_compatible<typename SubclassFactoryType<FUN>::Subclass>(); __assert_compatible<typename SubclassFactoryType<FUN>::Subclass>();
temporarilyInstallAlternateFactory (origInstance_, origFactory_ temporarilyInstallAlternateFactory (origInstance_, origFactory_
,[=]() ,[this, buildInstance=forward<FUN> (_buildInstance)]
{ {
mock_.reset (buildInstance()); mock_.reset (buildInstance());
return mock_.get(); return mock_.get();
}); });
} }
~Local() ~Local()
{ {

View file

@ -44,6 +44,7 @@
#define LIB_META_TUPLE_CLOSURE_H #define LIB_META_TUPLE_CLOSURE_H
#include "lib/meta/function-closure.hpp" #include "lib/meta/function-closure.hpp"
#include "lib/meta/tuple-helper.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
#include <utility> #include <utility>
@ -140,7 +141,7 @@ namespace meta{
auto auto
operator() (RemainingParams remPar) const operator() (RemainingParams remPar) const
{ {
return std::apply (unConst(this)->partialClosure_, remPar); return apply (unConst(this)->partialClosure_, remPar);
}; };
CLO partialClosure_; CLO partialClosure_;

View file

@ -42,6 +42,7 @@
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <functional>
namespace util { // forward declaration namespace util { // forward declaration
@ -78,6 +79,56 @@ namespace meta {
using disable_if_Tuple = lib::meta::disable_if<lib::meta::is_Tuple<std::remove_reference_t<TUP>>>; using disable_if_Tuple = lib::meta::disable_if<lib::meta::is_Tuple<std::remove_reference_t<TUP>>>;
namespace { // apply to tuple-like : helpers...
/** @internal invocation helper similar to C++17 — but preferring a custom `get` impl */
template<typename FUN, typename TUP, size_t...Idx>
constexpr decltype(auto)
__unpack_and_apply (FUN&& f, TUP&& tup, std::index_sequence<Idx...>)
{ // ▽▽▽ ADL
using std::get;
return std::invoke (std::forward<FUN> (f)
,get<Idx> (std::forward<TUP>(tup))...
);
}
/** @internal invoke a metafunction with \a FUN and all element types from \a TUP */
template<template<typename...> class META, class FUN, class TUP>
struct _InvokeMetafunTup
{
using Tupl = std::decay_t<TUP>;
using Elms = typename ElmTypes<Tupl>::Seq;
using Args = typename Prepend<FUN, Elms>::Seq;
using Type = typename RebindVariadic<META, Args>::Type;
};
template<class FUN, class TUP>
inline constexpr bool can_nothrow_invoke_tup = _InvokeMetafunTup<std::is_nothrow_invocable,FUN,TUP>::Type::value;
}
/**
* Replacement for `std::apply` yet applicable to _tuple-like custom types_.
* For unclear reasons, the standard chooses to reject such custom types, and
* only allows a fixed set of explicitly defined facilities from the Stdlib
* (tuple, pair, array, and some ranges stuff).
* @todo 6/2025 as a first step, this replicates the implementation from C++17;
* the second step would be to constrain this to a concept `tuple_like`
*/
template<class FUN, class TUP>
constexpr decltype(auto)
apply (FUN&& f, TUP&& tup) noexcept (can_nothrow_invoke_tup<FUN,TUP> )
{
using Indices = std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<TUP>>>;
return __unpack_and_apply (std::forward<FUN> (f)
,std::forward<TUP> (tup)
,Indices{}
);
}
/** /**
* Tuple iteration: perform some arbitrary operation on each element of a tuple. * Tuple iteration: perform some arbitrary operation on each element of a tuple.
* @note the given functor must be generic, since each position of the tuple * @note the given functor must be generic, since each position of the tuple
@ -87,7 +138,7 @@ namespace meta {
* then employ a fold expression with the comma operator. * then employ a fold expression with the comma operator.
*/ */
template<class TUP, class FUN, typename = enable_if_Tuple<TUP>> template<class TUP, class FUN, typename = enable_if_Tuple<TUP>>
void constexpr void
forEach (TUP&& tuple, FUN fun) forEach (TUP&& tuple, FUN fun)
{ {
std::apply ([&fun](auto&&... elms) std::apply ([&fun](auto&&... elms)
@ -112,7 +163,7 @@ namespace meta {
* is used, which is guaranteed to evaluate from left to right. * is used, which is guaranteed to evaluate from left to right.
*/ */
template<class TUP, class FUN, typename = enable_if_Tuple<TUP>> template<class TUP, class FUN, typename = enable_if_Tuple<TUP>>
auto constexpr auto
mapEach (TUP&& tuple, FUN fun) mapEach (TUP&& tuple, FUN fun)
{ {
return std::apply ([&fun](auto&&... elms) return std::apply ([&fun](auto&&... elms)

View file

@ -31,6 +31,13 @@
** the corresponding operators on the pointee and by allowing to specify a base class smart-ptr ** the corresponding operators on the pointee and by allowing to specify a base class smart-ptr
** as template parameter. ** as template parameter.
** **
** @deprecated 2025 : smells like an overly zealous design, while fundamental traits of the
** involved entities remain nebulous. Who is the »entity«? The pointer or the pointee?
** Why do we even want to delegate relational operators, while we do not even know that
** the target supports them? And why to we need an virtual equality? If these objects have
** reference semantics, then a base class should compare the identity. And there should not
** be any ordering on such elements. So the whole motivation of rolling a specialised
** shard-ptr seems moot. /////////////////////////////////////////////////////TICKET #501 : clarify Placement and MObject identity
** @see asset.hpp ** @see asset.hpp
** @see custom-shared-ptr-test.cpp ** @see custom-shared-ptr-test.cpp
** @see orderingofassetstest.cpp ** @see orderingofassetstest.cpp
@ -94,11 +101,11 @@ namespace lib {
private: /* === friend operators injected into enclosing namespace for ADL === */ private: /* === friend operators injected into enclosing namespace for ADL === */
//////////////////TICKET #932 Clang is unable to fill in the default template argument. Resolved in newer versions of Clang. Temporary workaround: add second parameter B ///////////////////TICKET #932 Clang is unable to fill in the default template argument. Resolved in newer versions of Clang. Temporary workaround: add second parameter B
template<typename _O_,typename B> template<typename _O_,typename B>
friend inline bool friend inline bool
operator== (P const& p, P<_O_, B> const& q) { return (p and q)? (*p == *q) : (!p and !q); } operator== (P const& p, P<_O_, B> const& q) { return (p and q)? (*p == *q) : (!p and !q); }
///////////////////////TICKET #501 : clarify Placement and MObject identity
template<typename _O_,typename B> template<typename _O_,typename B>
friend inline bool friend inline bool
operator!= (P const& p, P<_O_, B> const& q) { return (p and q)? (*p != *q) : !(!p and !q); } operator!= (P const& p, P<_O_, B> const& q) { return (p and q)? (*p != *q) : !(!p and !q); }

View file

@ -234,8 +234,8 @@ namespace lib {
return Tar{floor (val)}; return Tar{floor (val)};
} }
} //----headroom to accommodate low probabilities } //----headroom to accommodate low probabilities
static size_t constexpr QUANTISER = 1 << 4 + util::ilog2 (Tar::maxVal()-Tar::minVal()); static constexpr size_t QUANTISER = 1 << 4 + util::ilog2 (Tar::maxVal()-Tar::minVal());
static double constexpr CAP_EPSILON = 1/(2.0 * QUANTISER); static constexpr double CAP_EPSILON = 1/(2.0 * QUANTISER);
/** @internal draw from source of randomness */ /** @internal draw from source of randomness */

View file

@ -147,7 +147,7 @@ namespace lib {
* elements of type \a TY in memory _with proper alignment_. * elements of type \a TY in memory _with proper alignment_.
*/ */
template<typename TY> template<typename TY>
size_t inline constexpr inline constexpr size_t
reqSiz() reqSiz()
{ {
size_t quant = alignof(TY); size_t quant = alignof(TY);
@ -159,7 +159,7 @@ namespace lib {
} }
/** determine size of a reserve buffer to place with proper alignment */ /** determine size of a reserve buffer to place with proper alignment */
size_t inline constexpr inline constexpr size_t
alignRes (size_t alignment) alignRes (size_t alignment)
{ {
return positiveDiff (alignment, alignof(void*)); return positiveDiff (alignment, alignof(void*));

View file

@ -148,7 +148,7 @@ namespace lib {
Symbol& operator= (Symbol &&) = default; Symbol& operator= (Symbol &&) = default;
explicit operator bool() const { return not empty(); } explicit operator bool() const { return not empty(); }
bool empty() const { return *this == BOTTOM or *this == EMPTY; } bool empty() const { return *this == BOTTOM.c() or *this == EMPTY.c(); }
size_t size_t
length() const length() const

View file

@ -285,7 +285,7 @@ namespace time {
Duration Duration
FrameRate::duration() const FrameRate::duration() const
{ {
if (0 == *this) if (HALTED > *this)
throw error::Logic ("Impossible to quantise to an zero spaced frame grid" throw error::Logic ("Impossible to quantise to an zero spaced frame grid"
, error::LUMIERA_ERROR_BOTTOM_VALUE); , error::LUMIERA_ERROR_BOTTOM_VALUE);

View file

@ -451,28 +451,28 @@ namespace time {
int int
HmsTC::getSecs() const HmsTC::getSecs() const
{ /////////////////////////////////////////////////////////////////////////////////////////////////TICKET #750 we do not want numeric accessors her — rather we want Digxel members { /////////////////////////////////////////////////////////////////////////////////////////////////TICKET #750 we do not want numeric accessors her — rather we want Digxel members
return (raw_time_64(tpoint_) / TIME_SCALE_sec) % 60; return (_raw (tpoint_) / TIME_SCALE_sec) % 60;
} }
/** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */ /** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */
int int
HmsTC::getMins() const HmsTC::getMins() const
{ {
return (raw_time_64(tpoint_) / TIME_SCALE_sec / 60) % 60; return (_raw (tpoint_) / TIME_SCALE_sec / 60) % 60;
} }
/** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */ /** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */
int int
HmsTC::getHours() const HmsTC::getHours() const
{ {
return raw_time_64(tpoint_) / TIME_SCALE_sec / 60 / 60; return _raw (tpoint_) / TIME_SCALE_sec / 60 / 60;
} }
/** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */ /** @deprecated 5/25 : no numeric computations in this class! use Digxel instead! */
double double
HmsTC::getMillis() const HmsTC::getMillis() const
{ {
return (raw_time_64(tpoint_) / TIME_SCALE_ms) % 1000; return (_raw (tpoint_) / TIME_SCALE_ms) % 1000;
} }
/** */ /** */

View file

@ -191,7 +191,7 @@ namespace time {
static TimeValue buildRaw_(raw_time_64); static TimeValue buildRaw_(raw_time_64);
/** @internal diagnostics */ /** @internal diagnostics */
operator std::string () const; explicit operator std::string() const;
/** @return is in-domain, not a boundary value */ /** @return is in-domain, not a boundary value */
bool isRegular() const; bool isRegular() const;
@ -265,8 +265,6 @@ namespace time {
return *this; return *this;
} }
/// Support mixing with plain 64bit int arithmetics
operator raw_time_64() const { return t_; }
/// Support for micro-tick precise time arithmetics /// Support for micro-tick precise time arithmetics
operator FSecs() const { return FSecs{t_, TimeValue::SCALE}; } operator FSecs() const { return FSecs{t_, TimeValue::SCALE}; }
@ -342,7 +340,7 @@ namespace time {
); );
/** @internal diagnostics */ /** @internal diagnostics */
operator std::string () const; explicit operator std::string() const;
/** convenience start for time calculations */ /** convenience start for time calculations */
TimeVar operator+ (TimeValue const& tval) const { return TimeVar(*this) + tval; } TimeVar operator+ (TimeValue const& tval) const { return TimeVar(*this) + tval; }
@ -405,7 +403,7 @@ namespace time {
Offset stretchedByFloatFactor (double) const; Offset stretchedByFloatFactor (double) const;
/** @internal diagnostics, indicating ∆ */ /** @internal diagnostics, indicating ∆ */
operator std::string () const; explicit operator std::string() const;
// Supporting sign flip // Supporting sign flip
Offset operator- () const; Offset operator- () const;
@ -522,7 +520,7 @@ namespace time {
/** @internal diagnostics */ /** @internal diagnostics */
operator std::string () const; explicit operator std::string() const;
/// Supporting backwards use as offset /// Supporting backwards use as offset
Offset operator- () const; Offset operator- () const;
@ -651,7 +649,7 @@ namespace time {
void accept (Mutation const&); void accept (Mutation const&);
/** @internal diagnostics */ /** @internal diagnostics */
operator std::string () const; explicit operator std::string() const;
/// Supporting extended total order, based on start and interval length /// Supporting extended total order, based on start and interval length
friend bool operator== (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_==t2.t_ && t1.dur_==t2.dur_; } friend bool operator== (TimeSpan const& t1, TimeSpan const& t2) { return t1.t_==t2.t_ && t1.dur_==t2.dur_; }
@ -689,7 +687,10 @@ namespace time {
/** duration of one frame */ /** duration of one frame */
Duration duration() const; Duration duration() const;
operator std::string() const; /** derive total ordering from base class */
std::strong_ordering operator<=>(FrameRate const&) const = default;
explicit operator std::string() const;
}; };
/** convenient conversion to duration in fractional seconds */ /** convenient conversion to duration in fractional seconds */

View file

@ -30,7 +30,7 @@
namespace util { namespace util {
template<typename N> template<typename N>
inline bool constexpr inline constexpr bool
isPow2 (N n) isPow2 (N n)
{ {
return n > 0 and !(n & (n-1)); return n > 0 and !(n & (n-1));

View file

@ -40,9 +40,9 @@ namespace std {// forward declarations to avoid pervasive includes
class set; class set;
template<typename IT, typename V> template<typename IT, typename V>
IT find (IT, IT, V const&); constexpr IT find (IT, IT, V const&);
template<typename IT, typename V> template<typename IT, typename V>
IT remove (IT, IT, V const&); constexpr IT remove (IT, IT, V const&);
} }
@ -57,21 +57,21 @@ namespace util {
template <class NUM> template <class NUM>
inline int constexpr inline constexpr int
sgn (NUM n) sgn (NUM n)
{ {
return (n==0)? 0 :((n<0)? -1:+1 ); return (n==0)? 0 :((n<0)? -1:+1 );
} }
template <class N1, class N2> template <class N1, class N2>
inline N1 constexpr inline constexpr N1
min (N1 n1, N2 n2) min (N1 n1, N2 n2)
{ {
return n2 < n1? N1(n2) : n1; return n2 < n1? N1(n2) : n1;
} }
template <class N1, class N2> template <class N1, class N2>
inline N1 constexpr inline constexpr N1
max (N1 n1, N2 n2) max (N1 n1, N2 n2)
{ {
return n1 < n2? N1(n2) : n1; return n1 < n2? N1(n2) : n1;
@ -79,7 +79,7 @@ namespace util {
/** cut a numeric value to be >=0 */ /** cut a numeric value to be >=0 */
template <typename NUM> template <typename NUM>
inline NUM constexpr inline constexpr NUM
noneg (NUM val) noneg (NUM val)
{ {
return (0<val? val : 0); return (0<val? val : 0);
@ -87,7 +87,7 @@ namespace util {
/** force a numeric to be within bounds, inclusively */ /** force a numeric to be within bounds, inclusively */
template <typename NUM, typename NB> template <typename NUM, typename NB>
inline NUM constexpr inline constexpr NUM
limited (NB lowerBound, NUM val, NB upperBound) limited (NB lowerBound, NUM val, NB upperBound)
{ {
return min ( max (val, lowerBound) return min ( max (val, lowerBound)
@ -95,7 +95,7 @@ namespace util {
} }
template <typename NUM, typename NB> template <typename NUM, typename NB>
inline bool constexpr inline constexpr bool
isLimited (NB lowerBound, NUM val, NB upperBound) isLimited (NB lowerBound, NUM val, NB upperBound)
{ {
return lowerBound <= val return lowerBound <= val
@ -103,7 +103,7 @@ namespace util {
} }
template <typename UN, typename N2> template <typename UN, typename N2>
inline UN constexpr inline constexpr UN
positiveDiff (N2 newVal, UN refVal) positiveDiff (N2 newVal, UN refVal)
{ {
return UN(newVal) > refVal? UN(newVal) - refVal return UN(newVal) > refVal? UN(newVal) - refVal

View file

@ -113,8 +113,8 @@ namespace ctrl {
: queue_{} : queue_{}
, dispatcher_{} , dispatcher_{}
{ {
dispatcher_.connect( dispatcher_.connect([=,this]
[=]() {try { {try {
queue_.invoke(); queue_.invoke();
} }
catch (std::exception& problem) catch (std::exception& problem)

View file

@ -85,7 +85,7 @@ namespace stage {
void void
NotificationService::dispatchMsg (ID uiElement, lib::diff::GenNode&& uiMessage) NotificationService::dispatchMsg (ID uiElement, lib::diff::GenNode&& uiMessage)
{ {
dispatch_->event ([=]() dispatch_->event ([=,this]
{ {
ctrl::BusTerm::mark (uiElement, uiMessage); ctrl::BusTerm::mark (uiElement, uiMessage);
}); });
@ -136,7 +136,7 @@ namespace stage {
void void
NotificationService::mutate (ID uiElement, MutationMessage&& diff) NotificationService::mutate (ID uiElement, MutationMessage&& diff)
{ {
dispatch_->event ([=]() dispatch_->event ([=,this]
{ // apply and consume diff message stored within closure { // apply and consume diff message stored within closure
this->change (uiElement, move(unConst(diff))); this->change (uiElement, move(unConst(diff)));
}); });

View file

@ -231,7 +231,7 @@ namespace widget {
ms_seconds_ebox.set_can_focus(true); ms_seconds_ebox.set_can_focus(true);
auto connect_motion_event = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_motion_event = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_motion_notify_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_motion_notify_event), fieldID);
guiElm.signal_motion_notify_event().connect (handlerSlot); guiElm.signal_motion_notify_event().connect (handlerSlot);
@ -249,7 +249,7 @@ namespace widget {
connect_motion_event (ms_seconds_ebox, MS_Seconds); connect_motion_event (ms_seconds_ebox, MS_Seconds);
auto connect_button_press = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_button_press = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_press_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_press_event), fieldID);
guiElm.signal_button_press_event().connect (handlerSlot); guiElm.signal_button_press_event().connect (handlerSlot);
@ -267,7 +267,7 @@ namespace widget {
connect_button_press (ms_seconds_ebox, MS_Seconds); connect_button_press (ms_seconds_ebox, MS_Seconds);
auto connect_button_release = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_button_release = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_release_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_release_event), fieldID);
guiElm.signal_button_release_event().connect (handlerSlot); guiElm.signal_button_release_event().connect (handlerSlot);
@ -285,7 +285,7 @@ namespace widget {
connect_button_release (ms_seconds_ebox, MS_Seconds); connect_button_release (ms_seconds_ebox, MS_Seconds);
auto connect_scroll_event = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_scroll_event = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_scroll_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_button_scroll_event), fieldID);
guiElm.signal_scroll_event().connect (handlerSlot); guiElm.signal_scroll_event().connect (handlerSlot);
@ -303,7 +303,7 @@ namespace widget {
connect_scroll_event (ms_seconds_ebox, MS_Seconds); connect_scroll_event (ms_seconds_ebox, MS_Seconds);
auto connect_key_press = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_key_press = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_press_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_press_event), fieldID);
guiElm.signal_key_press_event().connect (handlerSlot); guiElm.signal_key_press_event().connect (handlerSlot);
@ -321,7 +321,7 @@ namespace widget {
connect_key_press (ms_seconds_ebox, MS_Seconds); connect_key_press (ms_seconds_ebox, MS_Seconds);
auto connect_key_release = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_key_release = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_release_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_key_release_event), fieldID);
guiElm.signal_key_release_event().connect (handlerSlot); guiElm.signal_key_release_event().connect (handlerSlot);
@ -339,7 +339,7 @@ namespace widget {
connect_key_release (ms_seconds_ebox, MS_Seconds); connect_key_release (ms_seconds_ebox, MS_Seconds);
auto connect_focus_gain = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_focus_gain = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_gain_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_gain_event), fieldID);
guiElm.signal_focus_in_event().connect (handlerSlot); guiElm.signal_focus_in_event().connect (handlerSlot);
@ -357,7 +357,7 @@ namespace widget {
connect_focus_gain (ms_seconds_ebox, MS_Seconds); connect_focus_gain (ms_seconds_ebox, MS_Seconds);
auto connect_focus_loss = [=](Gtk::EventBox& guiElm, Field fieldID) auto connect_focus_loss = [=,this](Gtk::EventBox& guiElm, Field fieldID)
{ {
auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_loss_event), fieldID); auto handlerSlot = bind (mem_fun(this, &TimeCode::field_focus_loss_event), fieldID);
guiElm.signal_focus_out_event().connect (handlerSlot); guiElm.signal_focus_out_event().connect (handlerSlot);
@ -1108,7 +1108,7 @@ namespace widget {
if (frames != 0 && frames * drag_accum < (_raw(current_time()))) if (frames != 0 && frames * drag_accum < (_raw(current_time())))
{ {
// minus because up is negative in computer-land // minus because up is negative in computer-land
pos = TimeValue (floor (pos - drag_accum * frames)); pos = TimeValue (floor (_raw(pos) - drag_accum * frames));
set (pos, false); set (pos, false);
} }
else else

View file

@ -136,7 +136,7 @@ namespace workspace {
bool bool
DockArea::hasPanel (const int description_index) DockArea::hasPanel (const int description_index)
{ {
return util::has_any (panels_, [=](panel::Panel* panel) return util::has_any (panels_, [&](panel::Panel* panel)
{ {
return getPanelType(panel) == description_index; return getPanelType(panel) == description_index;
}); });

View file

@ -131,7 +131,7 @@ namespace workspace {
bool bool
PanelManager::hasPanel (const int description_index) PanelManager::hasPanel (const int description_index)
{ {
return util::has_any (panels_, [=](panel::Panel* panel) return util::has_any (panels_, [&](panel::Panel* panel)
{ {
return getPanelType(panel) == description_index; return getPanelType(panel) == description_index;
}); });

View file

@ -356,7 +356,7 @@ namespace control {
runningLoop_ = runningLoop_ =
make_unique<DispatcherLoop>( make_unique<DispatcherLoop>(
[=](string* problemIndicator) [=,this](string* problemIndicator)
{ // when the Session thread ends.... { // when the Session thread ends....
SteamDispatcher::endRunningLoopState(); SteamDispatcher::endRunningLoopState();
termNotification (problemIndicator); termNotification (problemIndicator);

View file

@ -307,6 +307,8 @@ namespace engine {
{ {
builder.emplaceParamDataBlock (&block(), turnoutSys); builder.emplaceParamDataBlock (&block(), turnoutSys);
} }
///////////////OOO
Feed()= default;
}; };

View file

@ -37,7 +37,6 @@
#include "lib/p.hpp" #include "lib/p.hpp"
#include "lib/time/timevalue.hpp" #include "lib/time/timevalue.hpp"
#include <boost/operators.hpp>
#include <string> #include <string>
@ -69,8 +68,7 @@ namespace mobject {
*/ */
class MObject class MObject
: public Buildable, : public Buildable,
util::NonCopyable, util::NonCopyable
boost::equality_comparable< MObject >
{ {
protected: protected:
typedef lib::time::Duration Duration; typedef lib::time::Duration Duration;
@ -97,12 +95,21 @@ namespace mobject {
/** MObject self-test (usable for asserting) */ /** MObject self-test (usable for asserting) */
virtual bool isValid() const =0; virtual bool isValid() const =0;
virtual Duration& getLength() =0; ////////////////////TICKET #448 virtual Duration& getLength() =0; ///////////////////////////TICKET #448
virtual bool operator== (const MObject& oo) const =0; ///< needed for handling by lumiera::P /** needed for handling by lumiera::P
* @deprecated 2025 this seems not well motivated. lumiera::P was created
* to support comparisons, and now we do not know how to implement them,
* and thus we make the operation virtual. Are MObjects conceived as
* having value semantics? For reference semantics, comparing the
* »identity« should be sufficient
* @note 2025 changed to a predicate to cope with C++20 reversed operators.
*/
virtual bool isEquivalentTo (const MObject& oo) const =0; ////////////////////////////////////////TICKET #501 : clarify Placement and MObject identity
friend bool operator== (MObject const& o1, MObject const& o2) { return o1.isEquivalentTo(o2); }
protected: protected:
virtual string initShortID() const =0; virtual string initShortID() const =0;
}; };

View file

@ -31,9 +31,10 @@ namespace session {
/** default/fallback implementation of equality /** default/fallback implementation of equality
* using literal object identity (same address). * using literal object identity (same address).
* Required to enable handling by lumiera::P * Required to enable handling by lumiera::P
* @deprecated 2025, see comment in MObject ////////////////////////////////////////////////////////////TICKET #501 : clarify Placement and MObject identity
*/ */
bool bool
AbstractMO::operator== (const MObject& oo) const AbstractMO::isEquivalentTo (const MObject& oo) const
{ {
return (this == &oo); return (this == &oo);
} }

View file

@ -59,7 +59,7 @@ namespace session {
return length_; return length_;
} }
bool operator== (const MObject& oo) const; bool isEquivalentTo (const MObject& oo) const override;
protected: protected:
void void

View file

@ -94,9 +94,9 @@ namespace play {
{ {
shutdown_initiated_ = true; shutdown_initiated_ = true;
launchDetached ("Output shutdown supervisor" launchDetached ("Output shutdown supervisor"
,[=]{ ,[=,this]{
bringDown (completedSignal); bringDown (completedSignal);
}); });
} }
} }

View file

@ -59,7 +59,7 @@ namespace gear {
class EngineEvent class EngineEvent
{ {
protected: protected:
static size_t constexpr RAW_SIZ = 3; static constexpr size_t RAW_SIZ = 3;
using Storage = std::array<int64_t, RAW_SIZ>; using Storage = std::array<int64_t, RAW_SIZ>;
template<class DAT> template<class DAT>

View file

@ -82,9 +82,7 @@ namespace gear {
using lib::time::FSecs; using lib::time::FSecs;
using lib::time::Time; using lib::time::Time;
using std::atomic; using std::atomic;
using std::memory_order::memory_order_relaxed; using std::memory_order;
using std::memory_order::memory_order_acquire;
using std::memory_order::memory_order_release;
using std::chrono_literals::operator ""us; using std::chrono_literals::operator ""us;
using std::chrono::microseconds; using std::chrono::microseconds;
@ -129,8 +127,8 @@ namespace gear {
{ {
ThreadID expect_noThread; // expect no one else to be in... ThreadID expect_noThread; // expect no one else to be in...
return groomingToken_.compare_exchange_strong (expect_noThread, thisThread() return groomingToken_.compare_exchange_strong (expect_noThread, thisThread()
,memory_order_acquire // success also constitutes an acquire barrier ,memory_order::acquire // success also constitutes an acquire barrier
,memory_order_relaxed // failure has no synchronisation ramifications ,memory_order::relaxed // failure has no synchronisation ramifications
); );
} }
@ -145,7 +143,7 @@ namespace gear {
{ // expect that this thread actually holds the Grooming-Token { // expect that this thread actually holds the Grooming-Token
REQUIRE (groomingToken_.load(memory_order_relaxed) == thisThread()); REQUIRE (groomingToken_.load(memory_order_relaxed) == thisThread());
const ThreadID noThreadHoldsIt; const ThreadID noThreadHoldsIt;
groomingToken_.store (noThreadHoldsIt, memory_order_release); groomingToken_.store (noThreadHoldsIt, memory_order::release);
} }
/** /**

View file

@ -66,7 +66,7 @@ namespace gear {
work::performRandomisedSpin (size_t stepping, size_t randFact) work::performRandomisedSpin (size_t stepping, size_t randFact)
{ {
size_t degree = CONTEND_SOFT_FACTOR * (1+randFact) * stepping; size_t degree = CONTEND_SOFT_FACTOR * (1+randFact) * stepping;
for (volatile size_t i=0; i<degree; ++i) {/*SPIN*/} for (volatile size_t i=0; i<degree; ) { i=i+1; /*SPIN*/}
} }
/** /**

View file

@ -197,7 +197,7 @@ namespace test{
for (uint i=0; i<cnt; ++i) for (uint i=0; i<cnt; ++i)
{ {
uint increment = rand_.i(MAX_RAND_INCMT); uint increment = rand_.i(MAX_RAND_INCMT);
queue.feed ([=]() { countConsumerCall(increment); }); queue.feed ([=,this]{ countConsumerCall(increment); });
producerSum += increment; producerSum += increment;
usleep (delay); usleep (delay);
queue.invoke(); // NOTE: dequeue one functor added during our sleep queue.invoke(); // NOTE: dequeue one functor added during our sleep

View file

@ -112,7 +112,7 @@ namespace test{
quant (int testPoint) quant (int testPoint)
{ {
TimeVar quantised = this->gridLocal(TimeValue(testPoint)); TimeVar quantised = this->gridLocal(TimeValue(testPoint));
return int(quantised); return _raw(quantised);
} }
}; };

View file

@ -101,7 +101,7 @@ namespace test{
CHECK (!(var < ref) ); CHECK (!(var < ref) );
CHECK ( (var > ref) ); CHECK ( (var > ref) );
raw_time_64 rat(var); raw_time_64 rat = _raw(var);
CHECK (!(rat == ref) ); CHECK (!(rat == ref) );
CHECK ( (rat != ref) ); CHECK ( (rat != ref) );
CHECK ( (rat >= ref) ); CHECK ( (rat >= ref) );

View file

@ -62,9 +62,9 @@ namespace test{
{ {
TimeValue parsed = FMT::parse (timeSpec_, *grid_); TimeValue parsed = FMT::parse (timeSpec_, *grid_);
CHECK (parsed == expected, "parsing '%s' resulted in %s instead of %s" CHECK (parsed == expected, "parsing '%s' resulted in %s instead of %s"
, cStr(timeSpec_) , timeSpec_.c_str()
, cStr(Time(parsed)) , string{Time(parsed)}.c_str()
, cStr(Time(expected))); , string{Time(expected)}.c_str());
} }
void void

View file

@ -142,7 +142,7 @@ namespace test{
CHECK (var < Time::MAX); CHECK (var < Time::MAX);
CHECK (var > Time::MIN); CHECK (var > Time::MIN);
raw_time_64 raw (var); raw_time_64 raw = _raw(var);
CHECK (raw == org); CHECK (raw == org);
CHECK (raw > org - two); CHECK (raw > org - two);

View file

@ -83,7 +83,7 @@ namespace test {
AssetManager& aMang = AssetManager::instance(); AssetManager& aMang = AssetManager::instance();
CHECK (aMang.getAsset (mm1->getID()) == mm2); // record of mm1 was replaced by mm2 CHECK (aMang.getAsset (mm1->getID()) == mm2); // record of mm1 was replaced by mm2
CHECK (aMang.getAsset (mm2->getID()) == mm2); CHECK (aMang.getAsset (mm2->getID()) == mm2); ////////////////////////TICKET #501 : clarify Placement and MObject identity
CHECK (aMang.known (mm1->getID())); CHECK (aMang.known (mm1->getID()));
CHECK (aMang.known (mm2->getID())); CHECK (aMang.known (mm2->getID()));

View file

@ -82,7 +82,7 @@ namespace test {
return element_; return element_;
} }
operator string() const { return element_; } operator string() const { return util::toString(element_); }
friend bool friend bool

View file

@ -68,7 +68,7 @@ namespace test {
{ {
Placement<Clip>& pC = getPlacement<Clip>(); Placement<Clip>& pC = getPlacement<Clip>();
cout << "Clip on media : "<< pC->getMedia() <<"\n"; cout << "Clip on media : "<< pC->getMedia() <<"\n";
CHECK (pC->operator==(c)); CHECK (pC->isEquivalentTo(c));
log_ = string (pC); log_ = string (pC);
} }
void treat (AbstractMO&) void treat (AbstractMO&)

View file

@ -22,8 +22,6 @@
#include "lib/p.hpp" #include "lib/p.hpp"
#include <boost/operators.hpp>
namespace lib { namespace lib {
@ -37,15 +35,13 @@ namespace test{
struct X struct X
: boost::totally_ordered<X>
{ {
long x_; long x_;
X(long x=0) : x_(x) {} explicit X(long x=0) : x_(x) {}
operator long () { return x_; } operator long () { return x_; }
bool operator< (const X& ox) const { return x_ < ox.x_; } std::strong_ordering operator<=>(X const&) const = default;
bool operator== (const X& ox) const { return x_ == ox.x_; }
virtual ~X() {} // using RTTI virtual ~X() {} // using RTTI
}; };

View file

@ -27,6 +27,7 @@
#include <string> #include <string>
using lumiera::error::Fatal;
using lib::transformIterator; using lib::transformIterator;
using lib::iter_stl::snapshot; using lib::iter_stl::snapshot;
using lib::iter_stl::eachElm; using lib::iter_stl::eachElm;
@ -53,6 +54,12 @@ namespace test {
operator string() const { return "hey Joe!"; } operator string() const { return "hey Joe!"; }
}; };
class Bomb
{
public:
operator string() const { throw Fatal{"mistake"}; }
};
class AutoCounter class AutoCounter
@ -110,7 +117,7 @@ namespace test {
CHECK (toString (chatterer) == "hey Joe!"_expect); CHECK (toString (chatterer) == "hey Joe!"_expect);
CHECK (toString (&chatterer) == "↗hey Joe!"_expect); // pointer indicated CHECK (toString (&chatterer) == "↗hey Joe!"_expect); // pointer indicated
CHECK (toString (nullptr) == ""_expect); // runtime exception, caught CHECK (toString (Bomb{}) == ""_expect); // runtime exception, caught
CHECK (toString (true) == "true"_expect); // special handling for bool CHECK (toString (true) == "true"_expect); // special handling for bool
CHECK (toString (2+2 == 5) == "false"_expect); CHECK (toString (2+2 == 5) == "false"_expect);

View file

@ -660,7 +660,7 @@ namespace test {
*/ */
SessionThread(function<void(DiffSource*)> notifyGUI) SessionThread(function<void(DiffSource*)> notifyGUI)
: ThreadJoinable{"BusTerm_test: asynchronous diff mutation" : ThreadJoinable{"BusTerm_test: asynchronous diff mutation"
, [=] , [this,notifyGUI]
{ {
uint cnt = randGen_.i(MAX_RAND_BORGS); uint cnt = randGen_.i(MAX_RAND_BORGS);
for (uint i=0; i<cnt; ++i) for (uint i=0; i<cnt; ++i)
@ -719,8 +719,9 @@ namespace test {
usleep (100); usleep (100);
uiDispatcher.invoke(); uiDispatcher.invoke();
} }
session.join(); auto ok = session.join();
//------end-multithreaded-mutation--- //------end-multithreaded-mutation---
CHECK (ok);
// on rare occasions we (consumer thread) // on rare occasions we (consumer thread)
// prematurely empty the queue... // prematurely empty the queue...

View file

@ -213,7 +213,7 @@ namespace test{
commandHandler_ = newHandler; commandHandler_ = newHandler;
else else
commandHandler_ = commandHandler_ =
[=](GenNode const& cmd) [this](GenNode const& cmd)
{ {
log_.warn(_Fmt("NOT handling command-message %s in test-mode") % cmd); log_.warn(_Fmt("NOT handling command-message %s in test-mode") % cmd);
}; };
@ -226,7 +226,7 @@ namespace test{
stateMarkHandler_ = newHandler; stateMarkHandler_ = newHandler;
else else
stateMarkHandler_ = stateMarkHandler_ =
[=](ID subject, GenNode const& mark) [this](ID subject, GenNode const& mark)
{ {
log_.warn(_Fmt("NOT handling state-mark %s passed from %s in test-mode") log_.warn(_Fmt("NOT handling state-mark %s passed from %s in test-mode")
% mark % subject); % mark % subject);

View file

@ -209,7 +209,7 @@ namespace test {
bool showRes = true; ///< print result data bool showRes = true; ///< print result data
bool showRef = true; ///< calculate single threaded reference time bool showRef = true; ///< calculate single threaded reference time
static uint constexpr REPETITIONS{20}; static constexpr uint REPETITIONS{20};
BlockFlowAlloc bFlow{}; BlockFlowAlloc bFlow{};
EngineObserver watch{}; EngineObserver watch{};

View file

@ -1394,7 +1394,7 @@ namespace test {
for ( ; 0 < round; --round) for ( ; 0 < round; --round)
lib::hash::combine (scree,scree); lib::hash::combine (scree,scree);
sink = scree; sink = scree;
sink++; sink = sink + 1;
} }
void void
@ -1408,7 +1408,7 @@ namespace test {
for (size_t i=0; i<memBlock.size()-1; ++i) for (size_t i=0; i<memBlock.size()-1; ++i)
memBlock[i+1] += memBlock[i]; memBlock[i+1] += memBlock[i];
sink = *memBlock.back(); sink = *memBlock.back();
sink++; sink = sink + 1;
} }
double double

File diff suppressed because it is too large Load diff