2017-01-20 03:27:32 +01:00
|
|
|
|
/*
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MUTATION-MESSAGE.hpp - message to cause changes to generic model elements
|
2017-01-20 03:27:32 +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
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2017, Hermann Vosseler <Ichthyostega@web.de>
|
2017-01-20 03:27:32 +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.
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-13 07:07:06 +02:00
|
|
|
|
/** @file mutation-message.hpp
|
2017-01-20 03:27:32 +01:00
|
|
|
|
** Generic Message with an embedded diff, to describe changes to model elements.
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** The ability to create and apply such messages relies on the [diff framework](\ref diff-language.hpp).
|
|
|
|
|
|
** Using diff messages allows to describe and effect changes, without actually knowing much about the target.
|
|
|
|
|
|
** Sender and receiver just need to share some common assumptions about the abstract structure of the data.
|
2017-01-20 03:27:32 +01:00
|
|
|
|
**
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** The challenging part with this task is the fact that we need to pass such messages over abstraction barriers
|
|
|
|
|
|
** and even schedule them into another thread (the UI event thread). Yet diff application actually is a _pull operation,_
|
|
|
|
|
|
** which means there must be a callback actually to retrieve the diff content, and this callback will happen from
|
|
|
|
|
|
** the context of the receiver.
|
2017-01-20 03:46:48 +01:00
|
|
|
|
**
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** # Mutation messages on the UI-Bus
|
2017-01-20 03:27:32 +01:00
|
|
|
|
**
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** The UI-Bus offers a dedicated API to direct MutationMessages towards [UI-Elements](\ref model::Tangible).
|
|
|
|
|
|
** Each _tangible element in the UI,_ be it Widget or Controller, is designated by an unique ID. Sending a
|
|
|
|
|
|
** Mutation message causes the target to alter and reshape itself, to comply to the _diff sequence_ indicated
|
|
|
|
|
|
** and transported through the message -- since a diff sequence as such is always concrete and relates to a
|
|
|
|
|
|
** a specific context, we can not represent it directly as a type on interface level. Rather, the receiver
|
|
|
|
|
|
** of a diff sequence must offer the ability to be reshaped through diff messages, which is expressed through
|
2018-11-15 23:59:23 +01:00
|
|
|
|
** the interface DiffMutable. In the case at question here, stage::model::Tangible offers this interface and thus
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** the ability to construct a concrete lib::diff::TreeMutator, which in turn is bound to the internals of the
|
|
|
|
|
|
** actual UI-Element. In this framework, a diff is actually represented as a sequence of _diff verbs,_ which
|
|
|
|
|
|
** can be ``pulled'' one by one from the MutationMessage, and then applied to the target data structure
|
|
|
|
|
|
** with the help of a `DiffApplicator<DiffMutable>`, based on the TreeMutator exposed.
|
|
|
|
|
|
**
|
|
|
|
|
|
** # Mutation messages sent from the Session into the UI
|
|
|
|
|
|
**
|
|
|
|
|
|
** While components in the UI generate commands to work on the session, the effect of performing those commands
|
|
|
|
|
|
** is reflected back asynchronously into the GUI through MutationMessages. All _visible content in the UI_ is
|
|
|
|
|
|
** controlled by such messages. Initially the UI is a blank slate, and will be populated with content to reflect
|
|
|
|
|
|
** the content and structure of the session. Whenever the session changes, an incremental update is pushed into
|
|
|
|
|
|
** the UI as a diff.
|
|
|
|
|
|
**
|
|
|
|
|
|
** Hand-over and application of mutations is actually a process in two steps. The necessity to change something
|
|
|
|
|
|
** is indicated (or ``triggered'') by passing a MutationMessage through the GuiNotification::facade. We should
|
|
|
|
|
|
** note at this point that Session and UI perform each within a dedicated single thread (contrast this to the
|
|
|
|
|
|
** player and render engine, which are inherently multithreaded). The UI is loaded as plug-in and opens the
|
|
|
|
|
|
** GuiNotification::facade when the event loop is started. Thus _initiating_ the mutation process is a simple
|
|
|
|
|
|
** invocation from the session thread, which enqueues the MutationMessage and schedules the trigger over into
|
|
|
|
|
|
** the UI event thread. This starts the second stage of diff application: when the UI is about to process
|
|
|
|
|
|
** this event, the MutationMessage (which was passed through a dispatcher queue) will be forwarded over the
|
|
|
|
|
|
** UI-Bus to reach the designated target object. On reception, the receiving UI-Element builds and exposes
|
|
|
|
|
|
** its TreeMutator and the starts to _pull_ the individual DiffStep entries from the MutationMessage.
|
|
|
|
|
|
** But in fact those entries aren't stored within the message, rather a callback is invoked. When initially
|
|
|
|
|
|
** creating the message, an _opaque generation context_ was established, which now receives those callbacks
|
|
|
|
|
|
** and generates the actual sequence of diff verbs, which are immediately passed on to through the DiffApplicator
|
|
|
|
|
|
** and the TreeMutator to effect the corresponding changes in the target data structure within the UI. Care has
|
|
|
|
|
|
** to be taken when referring to session data at that point, since the pull happens from within the UI thread;
|
|
|
|
|
|
** yet in the end this remains an opaque implementation detail within the session.
|
|
|
|
|
|
**
|
|
|
|
|
|
** ## Creation of mutation messages
|
|
|
|
|
|
**
|
|
|
|
|
|
** The standard case is to build a MutationMessage by passing a heap allocated generator object. This DiffSource
|
|
|
|
|
|
** object needs to implement the interface lib::IterSource<DiffStep>, with callbacks to generate the initial
|
|
|
|
|
|
** step and further steps. Incidentally, the MutationMessage takes ownership and manages the DiffSource generator.
|
|
|
|
|
|
** Beyond this standard case, MutationMessage offers several convenience constructors to produce simple diff
|
|
|
|
|
|
** messages with a predetermined fixes sequence of DiffStep entries.
|
|
|
|
|
|
**
|
|
|
|
|
|
** @see MutationMessage_test
|
2017-08-10 23:42:55 +02:00
|
|
|
|
** @see AbstractTangible_test
|
2017-08-13 07:07:06 +02:00
|
|
|
|
** @see BustTerm_test::pushDiff()
|
2017-08-11 15:23:33 +02:00
|
|
|
|
** @see BusTerm::change()
|
2017-01-20 03:27:32 +01:00
|
|
|
|
**
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-13 07:09:06 +02:00
|
|
|
|
#ifndef LIB_DIFF_MUTATION_MESSAGE_H
|
|
|
|
|
|
#define LIB_DIFF_MUTATION_MESSAGE_H
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
2017-08-10 23:42:55 +02:00
|
|
|
|
#include "lib/iter-source.hpp"
|
2017-08-11 22:23:51 +02:00
|
|
|
|
#include "lib/iter-adapter-stl.hpp"
|
2017-08-10 23:42:55 +02:00
|
|
|
|
#include "lib/diff/tree-diff.hpp"
|
|
|
|
|
|
#include "lib/diff/gen-node.hpp"
|
2017-08-12 04:04:22 +02:00
|
|
|
|
#include "lib/format-util.hpp"
|
2017-08-11 21:27:51 +02:00
|
|
|
|
#include "lib/meta/util.hpp"
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-20 03:46:48 +01:00
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace diff{
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
using std::string;
|
2017-08-11 21:27:51 +02:00
|
|
|
|
using std::__and_;
|
|
|
|
|
|
using std::__not_;
|
|
|
|
|
|
using lib::meta::enable_if;
|
Library: introduce a concept for the »Lumiera Forward Iterator«
Well, finally.
Lumiera Iterators were conceived as a concept from the very beginning,
and this idea dates back even before C++11. Furthermore, over time some
''trait templates'' have been developed, to detect if some template argument
might match the known pattern of functions associated with a Lumiera Iterator.
Meanwhile this concept is used pervasively in the whole code base, and also
the traits templates proved to be reliable. It therefore seems that the time is ripe
to gradually introduce a genuine **concept** `lum_iter`
I'll take a defensive approach here, since any mistake would lead to
a massive breakage of compilation. The new concept is defined simply
by delegating to to the tried-and-tested trait template, which is
also renamed `can_IterForEach` ⟼ `can_LumieraIter`
One immediate benefit is that the compiler is now able to select
overloads based on that concept, which allows to drop the tricky
selection of variants based on the SFINAE technique and `enable_if`.
For validation, one very heavily used case of that pattern was switched
in `lib/format-util.hpp', which notably lies in the code-path used by `util::join`
2026-05-13 23:44:48 +02:00
|
|
|
|
using lib::meta::can_LumieraIter;
|
2017-08-11 21:27:51 +02:00
|
|
|
|
using lib::meta::can_STL_ForEach;
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
2017-08-10 23:42:55 +02:00
|
|
|
|
using DiffStep = TreeDiffLanguage::DiffStep;
|
|
|
|
|
|
using DiffSource = IterSource<DiffStep>;
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2017-08-10 23:42:55 +02:00
|
|
|
|
* Opaque message to effect a structural change on a target, which is
|
|
|
|
|
|
* likewise only known in an abstract way, as being specifically structured.
|
2023-10-05 01:50:54 +02:00
|
|
|
|
* Sending such messages typically allows some _implementation defined_ part within
|
2017-08-10 23:42:55 +02:00
|
|
|
|
* the Session to communicate structure and content to some other _implementation defined_
|
|
|
|
|
|
* part within the UI-Layer, without the necessity of both partners to be tightly coupled on
|
|
|
|
|
|
* implementation level or even know much about the other's implementation details. As motivation,
|
|
|
|
|
|
* contrast this to a naive UI implementation, which directly accesses some backend data structure;
|
|
|
|
|
|
* any change to the backend implementation typically affects the UI implementation on a detail level.
|
2017-08-13 07:07:06 +02:00
|
|
|
|
* @warning be sure to understand the fundamental problem of diff generation and application:
|
|
|
|
|
|
* the production context of diff messages need to be conserved beyond the producer's
|
|
|
|
|
|
* thread context, because it will be pulled asynchronous from within the UI event thread!
|
2017-01-20 03:27:32 +01:00
|
|
|
|
*/
|
2017-08-13 07:09:06 +02:00
|
|
|
|
struct MutationMessage
|
2017-08-11 02:00:54 +02:00
|
|
|
|
: DiffSource::iterator
|
2017-01-20 03:27:32 +01:00
|
|
|
|
{
|
2017-08-11 21:27:51 +02:00
|
|
|
|
using _FrontEnd = DiffSource::iterator;
|
|
|
|
|
|
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage() = default;
|
|
|
|
|
|
MutationMessage(MutationMessage&&) = default;
|
|
|
|
|
|
MutationMessage(MutationMessage const&) = default;
|
|
|
|
|
|
MutationMessage(MutationMessage& o) : MutationMessage((MutationMessage const&)o) { }
|
|
|
|
|
|
MutationMessage& operator= (MutationMessage const&) = default;
|
|
|
|
|
|
MutationMessage& operator= (MutationMessage &&) = default;
|
|
|
|
|
|
////////////////////////TICKET #963 Forwarding shadows copy operations
|
2017-08-11 02:00:54 +02:00
|
|
|
|
|
2017-08-10 23:42:55 +02:00
|
|
|
|
/**
|
2017-08-13 07:09:06 +02:00
|
|
|
|
* MutationMessage builder:
|
2017-08-10 23:42:55 +02:00
|
|
|
|
* take ownership of an opaque heap allocated context
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* from which the concrete diff can be pulled on demand
|
2017-08-10 23:42:55 +02:00
|
|
|
|
*/
|
2017-08-11 02:00:54 +02:00
|
|
|
|
explicit
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage(DiffSource* diffGenerationContext)
|
2017-08-11 21:27:51 +02:00
|
|
|
|
: _FrontEnd{DiffSource::build (diffGenerationContext)}
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
2017-08-11 22:23:51 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Convenience builder for consuming an brace enclosed initializer_list
|
2023-07-12 19:19:41 +02:00
|
|
|
|
* @note initialiser elements will be _copied_ into a _heap allocated_
|
2017-08-11 22:23:51 +02:00
|
|
|
|
* snapshot (vector), which is then managed by `shared_ptr`
|
|
|
|
|
|
*/
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage(std::initializer_list<DiffStep> const&& ili)
|
|
|
|
|
|
: MutationMessage{iter_stl::snapshot (move(ili))}
|
2017-08-11 22:23:51 +02:00
|
|
|
|
{ }
|
2017-08-11 22:31:02 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Convenience builder to take an arbitrary number of DiffStep arguments
|
|
|
|
|
|
* @note like for the initializer_list, arguments will be copied into
|
|
|
|
|
|
* a _heap allocated snapshot_
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename...ARGS>
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage(ARGS&& ...args)
|
|
|
|
|
|
: MutationMessage{ {std::forward<ARGS>(args)...} }
|
2017-08-11 22:31:02 +02:00
|
|
|
|
{ }
|
2017-08-11 22:23:51 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Convenience builder to piggyback any Lumiera Forward Iterator
|
|
|
|
|
|
* @note source iterator is copied into a heap allocated IterSource
|
|
|
|
|
|
*/
|
2017-08-11 21:27:51 +02:00
|
|
|
|
template<class IT>
|
Library: introduce a concept for the »Lumiera Forward Iterator«
Well, finally.
Lumiera Iterators were conceived as a concept from the very beginning,
and this idea dates back even before C++11. Furthermore, over time some
''trait templates'' have been developed, to detect if some template argument
might match the known pattern of functions associated with a Lumiera Iterator.
Meanwhile this concept is used pervasively in the whole code base, and also
the traits templates proved to be reliable. It therefore seems that the time is ripe
to gradually introduce a genuine **concept** `lum_iter`
I'll take a defensive approach here, since any mistake would lead to
a massive breakage of compilation. The new concept is defined simply
by delegating to to the tried-and-tested trait template, which is
also renamed `can_IterForEach` ⟼ `can_LumieraIter`
One immediate benefit is that the compiler is now able to select
overloads based on that concept, which allows to drop the tricky
selection of variants based on the SFINAE technique and `enable_if`.
For validation, one very heavily used case of that pattern was switched
in `lib/format-util.hpp', which notably lies in the code-path used by `util::join`
2026-05-13 23:44:48 +02:00
|
|
|
|
MutationMessage(IT&& ii, enable_if< can_LumieraIter<IT>, void*> =nullptr)
|
2017-08-11 23:52:13 +02:00
|
|
|
|
: _FrontEnd{iter_source::wrapIter (std::forward<IT>(ii))}
|
2017-08-10 23:42:55 +02:00
|
|
|
|
{ }
|
2017-08-11 22:23:51 +02:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Convenience builder to use elements form any STL-like container
|
|
|
|
|
|
* @note creating heap allocated IterSource, which _refers_ to the original container
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* @warning like with any classical iterators, the container must stay alive and accessible
|
2017-08-11 22:23:51 +02:00
|
|
|
|
*/
|
|
|
|
|
|
template<class CON>
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage(CON& container, enable_if< __and_< can_STL_ForEach<CON>
|
Library: introduce a concept for the »Lumiera Forward Iterator«
Well, finally.
Lumiera Iterators were conceived as a concept from the very beginning,
and this idea dates back even before C++11. Furthermore, over time some
''trait templates'' have been developed, to detect if some template argument
might match the known pattern of functions associated with a Lumiera Iterator.
Meanwhile this concept is used pervasively in the whole code base, and also
the traits templates proved to be reliable. It therefore seems that the time is ripe
to gradually introduce a genuine **concept** `lum_iter`
I'll take a defensive approach here, since any mistake would lead to
a massive breakage of compilation. The new concept is defined simply
by delegating to to the tried-and-tested trait template, which is
also renamed `can_IterForEach` ⟼ `can_LumieraIter`
One immediate benefit is that the compiler is now able to select
overloads based on that concept, which allows to drop the tricky
selection of variants based on the SFINAE technique and `enable_if`.
For validation, one very heavily used case of that pattern was switched
in `lib/format-util.hpp', which notably lies in the code-path used by `util::join`
2026-05-13 23:44:48 +02:00
|
|
|
|
,__not_<can_LumieraIter<CON>>>, void*> =nullptr)
|
2017-08-11 22:23:51 +02:00
|
|
|
|
: _FrontEnd{iter_source::eachEntry(container)}
|
|
|
|
|
|
{ }
|
2017-08-12 04:04:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* enable support to show content of the message.
|
|
|
|
|
|
* After calling this function, operator string() renders all DiffSteps
|
2017-08-13 07:09:06 +02:00
|
|
|
|
* @warning since by design a MutationMessage can only be ``pulled'' once,
|
2017-08-12 04:04:22 +02:00
|
|
|
|
* this operation needs to impose a _side effect:_ it materialises
|
|
|
|
|
|
* the complete diff sequence at once into a heap allocated buffer.
|
|
|
|
|
|
*/
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MutationMessage& updateDiagnostics();
|
2017-01-20 03:27:32 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
2017-08-12 14:33:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // Implementation: take snapshot to enable diagnostics
|
2017-08-12 04:04:22 +02:00
|
|
|
|
|
2017-08-12 14:33:26 +02:00
|
|
|
|
/** "materialised view" of the diff sequence */
|
2017-08-12 04:04:22 +02:00
|
|
|
|
struct DiffSnapshot
|
|
|
|
|
|
: std::vector<DiffStep>
|
|
|
|
|
|
{
|
2017-08-13 07:09:06 +02:00
|
|
|
|
DiffSnapshot(MutationMessage& srcMsg)
|
2017-08-12 04:04:22 +02:00
|
|
|
|
{
|
|
|
|
|
|
for ( ; srcMsg; ++srcMsg )
|
|
|
|
|
|
push_back (*srcMsg);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
using _VecIter = DiffSnapshot::iterator;
|
|
|
|
|
|
using _RangeIT = RangeIter<_VecIter>;
|
|
|
|
|
|
using _Wrapped = WrappedLumieraIter<_RangeIT>;
|
|
|
|
|
|
|
2017-08-12 14:33:26 +02:00
|
|
|
|
/**
|
2017-08-13 07:09:06 +02:00
|
|
|
|
* Decorator to be layered transparently on top of MutationMessage.
|
2017-08-12 14:33:26 +02:00
|
|
|
|
* Actually, what we do is to discharge the diff generator into
|
|
|
|
|
|
* the DiffSnapshot buffer and then replace the link to the original
|
|
|
|
|
|
* generator to this decorator, which, when iterated, yields the
|
|
|
|
|
|
* contents of the DiffSnapshot one by one. But since all DiffSteps
|
|
|
|
|
|
* are now stored into that DiffSnapshot _buffer we control,_ we're
|
|
|
|
|
|
* able to produce a diagnostic listing of the complete sequence.
|
|
|
|
|
|
*/
|
2017-08-13 07:09:06 +02:00
|
|
|
|
class MaterialisedDiffBuffer
|
2017-08-12 04:04:22 +02:00
|
|
|
|
: private DiffSnapshot
|
|
|
|
|
|
, public _Wrapped
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
2017-08-13 07:09:06 +02:00
|
|
|
|
MaterialisedDiffBuffer(MutationMessage& srcMsg)
|
2017-08-12 04:04:22 +02:00
|
|
|
|
: DiffSnapshot{srcMsg}
|
|
|
|
|
|
, _Wrapped{_RangeIT{DiffSnapshot::begin(), DiffSnapshot::end()}}
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
virtual
|
|
|
|
|
|
operator string() const override
|
|
|
|
|
|
{
|
|
|
|
|
|
return "Diff--{"+util::join (static_cast<DiffSnapshot> (*this))+"}";
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-12 14:33:26 +02:00
|
|
|
|
/** @par operational semantics
|
|
|
|
|
|
* Since the underlying generator of the DiffStep sequence is an iterator,
|
|
|
|
|
|
* the "materialised view" can only capture what's left at the point when
|
|
|
|
|
|
* updateDiagnostics() is invoked. The captured rest sequence seamlessly
|
|
|
|
|
|
* becomes the new generator and the old generator object is released,
|
|
|
|
|
|
* since the assignment of the new backend typically removes the last
|
|
|
|
|
|
* reference in the smart-ptr managing the generation backend. This
|
2018-09-21 13:46:42 +02:00
|
|
|
|
* process can be repeated and then the [diagnostics](\ref operator string())
|
2017-08-12 14:33:26 +02:00
|
|
|
|
* will show the remainder of the sequence _left at that point._
|
|
|
|
|
|
*/
|
2017-08-13 07:09:06 +02:00
|
|
|
|
inline MutationMessage&
|
|
|
|
|
|
MutationMessage::updateDiagnostics()
|
2017-08-12 04:04:22 +02:00
|
|
|
|
{
|
2017-08-13 07:09:06 +02:00
|
|
|
|
return *this = MutationMessage{new MaterialisedDiffBuffer(*this)};
|
2017-08-12 04:04:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-20 03:27:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-20 03:46:48 +01:00
|
|
|
|
}} // namespace lib::diff
|
2017-08-13 07:09:06 +02:00
|
|
|
|
#endif /*LIB_DIFF_MUTATION_MESSAGE_H*/
|