From 9707a8982ca196c04488605bd9a4804228c57fa5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 15 Dec 2014 03:21:19 +0100 Subject: [PATCH] Diff Handling and Diff Application: framework and definitions factored out of the concept test built last week. --- src/lib/diff/diff-language.hpp | 331 ++++------------ src/lib/diff/list-diff-application.hpp | 271 +------------ src/lib/diff/list-diff.hpp | 385 ++---------------- src/lib/diff/tree-diff-application.hpp | 382 +----------------- src/lib/diff/tree-diff.hpp | 392 ++----------------- tests/library/diff-list-application-test.cpp | 15 +- 6 files changed, 166 insertions(+), 1610 deletions(-) diff --git a/src/lib/diff/diff-language.hpp b/src/lib/diff/diff-language.hpp index f2c796acb..f0dd090b5 100644 --- a/src/lib/diff/diff-language.hpp +++ b/src/lib/diff/diff-language.hpp @@ -23,7 +23,57 @@ /** @file diff-language.hpp ** Fundamental definitions for a representation of changes. + ** We describe differences in data structures or changes to be applied + ** in the form of a "linearised diff language". Such a diff can be represented + ** as a sequence of tokens of constant size. Using a linearised constant size + ** representation allows to process diff generation and diff application in + ** a pipeline, enabling maximum decoupling of sender and receiver. + ** Changes sent by diff serve as a generic meta-representation to keep separate + ** and different representations of the same logical structure in sync. This allows + ** for tight cooperation between strictly separated components, without the need + ** of a fixed, predefined and shared data structure. ** + ** \par Basic Assumptions + ** While the \em linearisation folds knowledge about the underlying data structure + ** down into the actual diff, we deliberately assume that the data to be diffed is + ** \em structured data. Moreover, we'll assume implicitly that this data is \em typed, + ** and we'll assume explicitly that the atomic elements in the data structure have a + ** well-defined identity and can be compared with the \c == operator. We treat those + ** elements as values, which can be copied and moved cheaply. We include a copy of + ** all content elements right within the tokens of the diff language, either to + ** send the actual content data this way, or to serve as redundancy to verify + ** proper application of the changes at the diff receiver. + ** + ** \par Solution Pattern + ** The representation of this linearised diff language relies on a specialised form + ** of the visitor pattern: We assume the vocabulary of the diff language to be + ** relatively fixed, while the actual effect when consuming the stream of diff tokens + ** is provided as a private detail of the receiver, implemented as a concrete "Interpreter" + ** (visitor) of the specific diff language flavour in use. Thus, our implementation relies + ** on \em double-dispatch, based both on the type of the individual diff tokens and on the + ** concrete implementation of the Interpreter. The typical usage will employ an DiffApplicator, + ** so the "interpretation" of the language means to apply it to a target data structure in + ** this standard case. + ** + ** Due to the nature of double-dispatch, the interpretation of each token requires two + ** indirections. The first indirection forwards to a handler function corresponding to the + ** token, while the second indirection uses the VTable of the concrete Interpreter to pick + ** the actual implementation of this handler function for this specific case. Basically + ** the individual token ("verb") in the language is characterised by the handler function + ** it corresponds to (thus the meaning of a \em verb, an operation). To support diagnostics, + ** each token also bears a string id. And in addition, each token carries a single data + ** content element as argument. The idea is, that the "verbs", the handler functions and + ** the symbolic IDs are named alike (use the macro DiffStep_CTOR to define the tokens + ** in according to that rule). Such a combination of verb and data argument is called + ** a DiffStep, since it represents a single step in the process of describing changes + ** or transforming a data structure. For example, a list diff language can be built + ** using the following four verbs: + ** - pick-next + ** - insert-new + ** - delete-next + ** - push-back-next + ** + ** @see list-diff-application.hpp ** @see diff-list-application-test.cpp ** @see VerbToken ** @@ -34,32 +84,36 @@ #define LIB_DIFF_DIFF_LANGUAGE_H -#include "lib/test/run.hpp" +#include "lib/error.hpp" #include "lib/verb-token.hpp" -#include "lib/util.hpp" -#include "lib/iter-adapter-stl.hpp" -#include "lib/format-string.hpp" #include -#include -#include -#include -#include #include -using util::isnil; -using std::string; -using util::_Fmt; -using std::vector; -using std::move; namespace lib { -namespace test{ +namespace diff{ + namespace error = lumiera::error; LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected."); + /** + * Definition frame for a language to describe differences in data structures. + * We use a \em linearised representation as a sequence of DiffStep messages + * of constant size. The actual verbs of the diff language in use are defined + * through the operations of the \em Interpreter; each #VerbToken corresponds + * to a handler function on the Interpreter interface. In addition to the verb, + * each DiffStep also carries an content data element, like e.g. "insert elm + * at next position". + * @param I Interpreter interface of the actual language to use + * @param E type of the elementary data elements. + * @remarks recommendation is to set up a builder function for each distinct + * kind of verb to be used in the actual language: this #diffTokenBuilder + * takes the data element as argument and wraps a copy in the created + * DiffStep of the specific kind it is configured for. + */ template< class I, typename E> struct DiffLanguage { @@ -94,6 +148,7 @@ namespace test{ using HandlerFun = void (I::*) (E); + template struct DiffStepBuilder; @@ -143,141 +198,27 @@ namespace test{ const auto _ID_ = diffTokenBuilder (&Interpreter::_ID_, STRINGIFY(_ID_)); - template - class ListDiffInterpreter - { - public: - virtual ~ListDiffInterpreter() { } ///< this is an interface - - virtual void ins(E e) =0; - virtual void del(E e) =0; - virtual void pick(E e) =0; - virtual void push(E e) =0; - }; - - template - using ListDiffLanguage = DiffLanguage, E>; - template - class DiffApplicationStrategy; + + + + /* ==== Implementation Pattern for Diff Application ==== */ /** - * concrete strategy to apply a list diff to a target sequence given as vector. - * The implementation swaps aside the existing content of the target sequence - * and then consumes it step by step, while building up the altered content - * within the previously emptied target vector. Whenever possible, elements - * are moved directly to the target location. - * @throws lumiera::error::State when diff application fails due to the - * target sequence being different than assumed by the given diff. - * @warning behaves only EX_SANE in case of diff application errors, - * i.e. only partially modified / rebuilt sequence might be - * in the target when diff application is aborted + * Extension point: define how a specific diff language + * can be applied to elements in a concrete container + * @remarks the actual diff fed to the DiffApplicator + * assumes that this DiffApplicationStrategy is + * an Interpreter for the given diff language. + * @warning the actual language remains unspecified; + * it is picked from the visible context. */ - template - class DiffApplicationStrategy> - : public ListDiffInterpreter - { - using Vec = vector; - using Iter = typename Vec::iterator; - - Vec orig_; - Vec& seq_; - Iter pos_; - - bool - end_of_target() - { - return pos_ == orig_.end(); - } - - void - __expect_in_target (E const& elm, Literal oper) - { - if (end_of_target()) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "no (further) elements in target sequence") % oper % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - if (*pos_ != elm) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "found element %s on current target position instead") - % oper % elm % *pos_ - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_further_elements() - { - if (end_of_target()) - throw error::State("Premature end of target sequence; unable to apply diff further." - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_found (E const& elm, Iter const& targetPos) - { - if (targetPos == orig_.end()) - throw error::State(_Fmt("Premature end of sequence; unable to locate " - "element %s as reference point in target.") % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - - /* == Implementation of the diff application primitives == */ - - void - ins (E elm) - { - seq_.push_back(elm); - } - - void - del (E elm) - { - __expect_in_target(elm, "remove"); - ++pos_; - } - - void - pick (E elm) - { - __expect_in_target(elm, "pick"); - seq_.push_back (move(*pos_)); - ++pos_; - } - - void - push (E anchor) - { - __expect_further_elements(); - E elm(move(*pos_)); // consume current source element - ++pos_; - - // locate the insert position behind the given reference anchor - Iter insertPos = std::find(pos_, orig_.end(), anchor); - __expect_found (anchor, insertPos); - - // inserting the "pushed back" element behind the found position - // this might lead to reallocation and thus invalidate the iterators - auto currIdx = pos_ - orig_.begin(); - orig_.insert (++insertPos, move(elm)); - pos_ = orig_.begin() + currIdx; - } - - - public: - explicit - DiffApplicationStrategy(vector& targetVector) - : seq_(targetVector) - , pos_(seq_.begin()) - { - swap (seq_, orig_); // pos_ still refers to original input sequence, which has been moved to orig_ - seq_.reserve (targetVector.size() * 120 / 100); // heuristics for storage pre-allocation - } - }; + template + class DiffApplicationStrategy; /** @@ -285,7 +226,7 @@ namespace test{ * The usage pattern is as follows * #. construct a DiffApplicator instance, wrapping the target sequence * #. feed the list diff (sequence of diff verbs) to the #consume function - * #. the wrapped target sequence has been altered, to conform to the given diff + * #. the wrapped target sequence has been altered, to conform to the given diff * @note a suitable DiffApplicationStrategy will be picked, based on the type * of the concrete target sequence given at construction. (Effectively * this means you need a suitable DiffApplicationStrategy specialisation, @@ -295,9 +236,9 @@ namespace test{ class DiffApplicator : boost::noncopyable { - using Receiver = DiffApplicationStrategy; + using Interpreter = DiffApplicationStrategy; - Receiver target_; + Interpreter target_; public: explicit @@ -314,105 +255,7 @@ namespace test{ } }; - namespace { - template - using ContentSnapshot = iter_stl::IterSnapshot; - } - - template - inline ContentSnapshot - snapshot(CON const& con) - { - return ContentSnapshot(begin(con), end(con)); - } - - template - inline iter_stl::IterSnapshot - snapshot(std::initializer_list const&& ili) - { - using OnceIter = iter_stl::IterSnapshot; - return OnceIter(begin(ili), end(ili)); - } - - namespace {//Test fixture.... - - using DataSeq = vector; - - #define TOK(id) id(STRINGIFY(id)) - - string TOK(a1), TOK(a2), TOK(a3), TOK(a4), TOK(a5); - string TOK(b1), TOK(b2), TOK(b3), TOK(b4); - - using Interpreter = ListDiffInterpreter; - using DiffStep = ListDiffLanguage::DiffStep; - using DiffSeq = iter_stl::IterSnapshot; - - DiffStep_CTOR(ins); - DiffStep_CTOR(del); - DiffStep_CTOR(pick); - DiffStep_CTOR(push); - - - inline DiffSeq - generateTestDiff() - { - return snapshot({del(a1) - , del(a2) - , ins(b1) - , pick(a3) - , push(a5) - , pick(a5) - , ins(b2) - , ins(b3) - , pick(a4) - , ins(b4) - }); - - } - }//(End)Test fixture - - - - - - - - /***********************************************************************//** - * @test Demonstration/Concept: a description language for list differences. - * The representation is given as a linearised sequence of verb tokens. - * This test demonstrates the application of such a diff representation - * to a given source list, transforming this list to hold the intended - * target list contents. - * - * @see session-structure-mapping-test.cpp - */ - class DiffListApplication_test : public Test - { - - virtual void - run (Arg) - { - DataSeq src({a1,a2,a3,a4,a5}); - auto diff = generateTestDiff(); - CHECK (!isnil (diff)); - - DataSeq target = src; - DiffApplicator application(target); - application.consume(diff); - - CHECK (isnil (diff)); - CHECK (!isnil (target)); - CHECK (src != target); - CHECK (target == DataSeq({b1,a3,a5,b2,b3,a4,b4})); - } - }; - - - /** Register this test class... */ - LAUNCHER (DiffListApplication_test, "unit common"); - - - -}} // namespace lib::test +}} // namespace lib::diff +#endif /*LIB_DIFF_DIFF_LANGUAGE_H*/ diff --git a/src/lib/diff/list-diff-application.hpp b/src/lib/diff/list-diff-application.hpp index f5bb2315d..f41e1778c 100644 --- a/src/lib/diff/list-diff-application.hpp +++ b/src/lib/diff/list-diff-application.hpp @@ -22,10 +22,16 @@ /** @file list-diff-application.hpp - ** Fundamental definitions for a representation of changes. + ** Apply a "list diff" to a concrete sequence of elements in a container. + ** This header provides specialisation(s) of the DiffApplicationStrategy to + ** actual containers, choosing an implementation approach suitable for this + ** specific kind of container. Together with a #DiffApplicator, this allows + ** to receive the description of changes (as a linearised sequence of + ** DiffStep tokens) and apply them to a given concrete sequence of data + ** elements, thereby transforming the contents of this target sequence. ** ** @see diff-list-application-test.cpp - ** @see VerbToken + ** @see ListDiffLanguage ** */ @@ -34,136 +40,20 @@ #define LIB_DIFF_LIST_DIFF_APPLICATION_H -#include "lib/test/run.hpp" -#include "lib/verb-token.hpp" -#include "lib/util.hpp" -#include "lib/iter-adapter-stl.hpp" +#include "lib/diff/list-diff.hpp" #include "lib/format-string.hpp" -#include -#include #include -#include #include #include -using util::isnil; -using std::string; -using util::_Fmt; -using std::vector; -using std::move; - namespace lib { -namespace test{ - namespace error = lumiera::error; +namespace diff{ - LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected."); - - template< class I, typename E> - struct DiffLanguage - { - - using DiffVerb = VerbToken; - using VerbTok = std::tuple; - - struct DiffStep - : VerbTok - { - DiffVerb& verb() { return std::get<0>(*this); } - E elm() { return std::get<1>(*this); } - - DiffStep(DiffVerb verb, E e) - : VerbTok(verb,e) - { } - - operator string() const - { - return string(verb()) + "("+string(elm())+")"; - } - - void - applyTo (I& interpreter) - { - verb().applyTo (interpreter, elm()); - } - }; - }; - - template - using HandlerFun = void (I::*) (E); - - - template - struct DiffStepBuilder; - - /** generator to produce specific language tokens */ - template - struct DiffStepBuilder> - { - using Lang = DiffLanguage; - using Step = typename Lang::DiffStep; - using Verb = typename Lang::DiffVerb; - - HandlerFun handler; - Literal id; - - Step - operator() (E elm) const - { - return { Verb(handler,id), elm }; - } - }; - - - /** set up a diff language token generator, - * based on the specific handler function given. - * This generator will produce tokens, wrapping concrete content elements - * of type \c E. In the end, the purpose is to send a sequence of such tokens - * around, to feed them to a consumer, which implements the \em Interpreter - * interface of the diff language. E.g. this consumer might apply the diff. - */ - template - inline DiffStepBuilder - diffTokenBuilder (H handlerFun, Literal id) - { - return { handlerFun, id }; - } - -/** shortcut to define tokens of the diff language. - * Use it to define namespace level function objects, which, - * when supplied with an argument value of type \c E, will generate - * a specific language token wrapping a copy of this element. - * @note need a typedef \c Interpreter at usage site - * to refer to the actual language interpreter interface; - * the template parameters of the Language and the element - * type will be picked up from the given member function pointer. - */ -#define DiffStep_CTOR(_ID_) \ - const auto _ID_ = diffTokenBuilder (&Interpreter::_ID_, STRINGIFY(_ID_)); - - - template - class ListDiffInterpreter - { - public: - virtual ~ListDiffInterpreter() { } ///< this is an interface - - virtual void ins(E e) =0; - virtual void del(E e) =0; - virtual void pick(E e) =0; - virtual void push(E e) =0; - }; - - template - using ListDiffLanguage = DiffLanguage, E>; - - - - - - template - class DiffApplicationStrategy; + using util::_Fmt; + using std::vector; + using std::move; /** * concrete strategy to apply a list diff to a target sequence given as vector. @@ -280,139 +170,8 @@ namespace test{ }; - /** - * generic builder to apply a list diff to a given target sequence. - * The usage pattern is as follows - * #. construct a DiffApplicator instance, wrapping the target sequence - * #. feed the list diff (sequence of diff verbs) to the #consume function - * #. the wrapped target sequence has been altered, to conform to the given diff - * @note a suitable DiffApplicationStrategy will be picked, based on the type - * of the concrete target sequence given at construction. (Effectively - * this means you need a suitable DiffApplicationStrategy specialisation, - * e.g. for a target sequence within a vector) - */ - template - class DiffApplicator - : boost::noncopyable - { - using Receiver = DiffApplicationStrategy; - - Receiver target_; - - public: - explicit - DiffApplicator(SEQ& targetSeq) - : target_(targetSeq) - { } - - template - void - consume (DIFF&& diff) - { - for ( ; diff; ++diff ) - diff->applyTo(target_); - } - }; - - namespace { - template - using ContentSnapshot = iter_stl::IterSnapshot; - } - - template - inline ContentSnapshot - snapshot(CON const& con) - { - return ContentSnapshot(begin(con), end(con)); - } - - template - inline iter_stl::IterSnapshot - snapshot(std::initializer_list const&& ili) - { - using OnceIter = iter_stl::IterSnapshot; - return OnceIter(begin(ili), end(ili)); - } - - namespace {//Test fixture.... - - using DataSeq = vector; - - #define TOK(id) id(STRINGIFY(id)) - - string TOK(a1), TOK(a2), TOK(a3), TOK(a4), TOK(a5); - string TOK(b1), TOK(b2), TOK(b3), TOK(b4); - - using Interpreter = ListDiffInterpreter; - using DiffStep = ListDiffLanguage::DiffStep; - using DiffSeq = iter_stl::IterSnapshot; - - DiffStep_CTOR(ins); - DiffStep_CTOR(del); - DiffStep_CTOR(pick); - DiffStep_CTOR(push); - - - inline DiffSeq - generateTestDiff() - { - return snapshot({del(a1) - , del(a2) - , ins(b1) - , pick(a3) - , push(a5) - , pick(a5) - , ins(b2) - , ins(b3) - , pick(a4) - , ins(b4) - }); - - } - }//(End)Test fixture - - - - - - - /***********************************************************************//** - * @test Demonstration/Concept: a description language for list differences. - * The representation is given as a linearised sequence of verb tokens. - * This test demonstrates the application of such a diff representation - * to a given source list, transforming this list to hold the intended - * target list contents. - * - * @see session-structure-mapping-test.cpp - */ - class DiffListApplication_test : public Test - { - - virtual void - run (Arg) - { - DataSeq src({a1,a2,a3,a4,a5}); - auto diff = generateTestDiff(); - CHECK (!isnil (diff)); - - DataSeq target = src; - DiffApplicator application(target); - application.consume(diff); - - CHECK (isnil (diff)); - CHECK (!isnil (target)); - CHECK (src != target); - CHECK (target == DataSeq({b1,a3,a5,b2,b3,a4,b4})); - } - }; - - - /** Register this test class... */ - LAUNCHER (DiffListApplication_test, "unit common"); - - - -}} // namespace lib::test +}} // namespace lib::diff +#endif /*LIB_DIFF_LIST_DIFF_APPLICATION_H*/ diff --git a/src/lib/diff/list-diff.hpp b/src/lib/diff/list-diff.hpp index 9bf23ae16..e0b3068fc 100644 --- a/src/lib/diff/list-diff.hpp +++ b/src/lib/diff/list-diff.hpp @@ -22,8 +22,13 @@ /** @file list-diff.hpp - ** Fundamental definitions for a representation of changes. + ** A token language to represent changes in a list of elements. + ** In combination with the #DiffLanguage framework, this building block + ** defines the set of operations to express changes in a given list of elements. + ** By implementing the #ListDiffInterpreter interface (visitor), a concrete usage + ** can receive such a diff description and e.g. apply it to a target data structure. ** + ** @see diff-language.cpp ** @see diff-list-application-test.cpp ** @see VerbToken ** @@ -34,115 +39,30 @@ #define LIB_DIFF_LIST_DIFF_H -#include "lib/test/run.hpp" -#include "lib/verb-token.hpp" -#include "lib/util.hpp" -#include "lib/iter-adapter-stl.hpp" -#include "lib/format-string.hpp" - -#include -#include -#include -#include -#include -#include - -using util::isnil; -using std::string; -using util::_Fmt; -using std::vector; -using std::move; +#include "lib/diff/diff-language.hpp" namespace lib { -namespace test{ - namespace error = lumiera::error; - - LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected."); - - template< class I, typename E> - struct DiffLanguage - { - - using DiffVerb = VerbToken; - using VerbTok = std::tuple; - - struct DiffStep - : VerbTok - { - DiffVerb& verb() { return std::get<0>(*this); } - E elm() { return std::get<1>(*this); } - - DiffStep(DiffVerb verb, E e) - : VerbTok(verb,e) - { } - - operator string() const - { - return string(verb()) + "("+string(elm())+")"; - } - - void - applyTo (I& interpreter) - { - verb().applyTo (interpreter, elm()); - } - }; - }; - - template - using HandlerFun = void (I::*) (E); +namespace diff{ - template - struct DiffStepBuilder; - - /** generator to produce specific language tokens */ - template - struct DiffStepBuilder> - { - using Lang = DiffLanguage; - using Step = typename Lang::DiffStep; - using Verb = typename Lang::DiffVerb; - - HandlerFun handler; - Literal id; - - Step - operator() (E elm) const - { - return { Verb(handler,id), elm }; - } - }; - - - /** set up a diff language token generator, - * based on the specific handler function given. - * This generator will produce tokens, wrapping concrete content elements - * of type \c E. In the end, the purpose is to send a sequence of such tokens - * around, to feed them to a consumer, which implements the \em Interpreter - * interface of the diff language. E.g. this consumer might apply the diff. + /** + * Interpreter interface to define the operations ("verbs"), + * which describe differences or changes in a given list of data elements. + * The meaning of the verbs is as follows: + * - \c ins prompts to insert the given argument element at the \em current + * processing position into the target sequence. This operation + * allows to inject new data + * - \c del requires to delete the \em next element at \em current position. + * For sake of verification, the element to be deleted is also + * included as argument (redundancy). + * - \c pick just accepts the \em next element at \em current position into + * the resulting altered sequence. The element is given redundantly. + * - \c push effects a re-ordering of the target list contents: it requires + * to \em push the \em next element at \em current processing position + * back further into the list, to be placed at a position \em behind + * the reference element given as argument. */ - template - inline DiffStepBuilder - diffTokenBuilder (H handlerFun, Literal id) - { - return { handlerFun, id }; - } - -/** shortcut to define tokens of the diff language. - * Use it to define namespace level function objects, which, - * when supplied with an argument value of type \c E, will generate - * a specific language token wrapping a copy of this element. - * @note need a typedef \c Interpreter at usage site - * to refer to the actual language interpreter interface; - * the template parameters of the Language and the element - * type will be picked up from the given member function pointer. - */ -#define DiffStep_CTOR(_ID_) \ - const auto _ID_ = diffTokenBuilder (&Interpreter::_ID_, STRINGIFY(_ID_)); - - template class ListDiffInterpreter { @@ -161,258 +81,5 @@ namespace test{ - - template - class DiffApplicationStrategy; - - /** - * concrete strategy to apply a list diff to a target sequence given as vector. - * The implementation swaps aside the existing content of the target sequence - * and then consumes it step by step, while building up the altered content - * within the previously emptied target vector. Whenever possible, elements - * are moved directly to the target location. - * @throws lumiera::error::State when diff application fails due to the - * target sequence being different than assumed by the given diff. - * @warning behaves only EX_SANE in case of diff application errors, - * i.e. only partially modified / rebuilt sequence might be - * in the target when diff application is aborted - */ - template - class DiffApplicationStrategy> - : public ListDiffInterpreter - { - using Vec = vector; - using Iter = typename Vec::iterator; - - Vec orig_; - Vec& seq_; - Iter pos_; - - bool - end_of_target() - { - return pos_ == orig_.end(); - } - - void - __expect_in_target (E const& elm, Literal oper) - { - if (end_of_target()) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "no (further) elements in target sequence") % oper % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - if (*pos_ != elm) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "found element %s on current target position instead") - % oper % elm % *pos_ - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_further_elements() - { - if (end_of_target()) - throw error::State("Premature end of target sequence; unable to apply diff further." - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_found (E const& elm, Iter const& targetPos) - { - if (targetPos == orig_.end()) - throw error::State(_Fmt("Premature end of sequence; unable to locate " - "element %s as reference point in target.") % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - - /* == Implementation of the diff application primitives == */ - - void - ins (E elm) - { - seq_.push_back(elm); - } - - void - del (E elm) - { - __expect_in_target(elm, "remove"); - ++pos_; - } - - void - pick (E elm) - { - __expect_in_target(elm, "pick"); - seq_.push_back (move(*pos_)); - ++pos_; - } - - void - push (E anchor) - { - __expect_further_elements(); - E elm(move(*pos_)); // consume current source element - ++pos_; - - // locate the insert position behind the given reference anchor - Iter insertPos = std::find(pos_, orig_.end(), anchor); - __expect_found (anchor, insertPos); - - // inserting the "pushed back" element behind the found position - // this might lead to reallocation and thus invalidate the iterators - auto currIdx = pos_ - orig_.begin(); - orig_.insert (++insertPos, move(elm)); - pos_ = orig_.begin() + currIdx; - } - - - public: - explicit - DiffApplicationStrategy(vector& targetVector) - : seq_(targetVector) - , pos_(seq_.begin()) - { - swap (seq_, orig_); // pos_ still refers to original input sequence, which has been moved to orig_ - seq_.reserve (targetVector.size() * 120 / 100); // heuristics for storage pre-allocation - } - }; - - - /** - * generic builder to apply a list diff to a given target sequence. - * The usage pattern is as follows - * #. construct a DiffApplicator instance, wrapping the target sequence - * #. feed the list diff (sequence of diff verbs) to the #consume function - * #. the wrapped target sequence has been altered, to conform to the given diff - * @note a suitable DiffApplicationStrategy will be picked, based on the type - * of the concrete target sequence given at construction. (Effectively - * this means you need a suitable DiffApplicationStrategy specialisation, - * e.g. for a target sequence within a vector) - */ - template - class DiffApplicator - : boost::noncopyable - { - using Receiver = DiffApplicationStrategy; - - Receiver target_; - - public: - explicit - DiffApplicator(SEQ& targetSeq) - : target_(targetSeq) - { } - - template - void - consume (DIFF&& diff) - { - for ( ; diff; ++diff ) - diff->applyTo(target_); - } - }; - - namespace { - template - using ContentSnapshot = iter_stl::IterSnapshot; - } - - template - inline ContentSnapshot - snapshot(CON const& con) - { - return ContentSnapshot(begin(con), end(con)); - } - - template - inline iter_stl::IterSnapshot - snapshot(std::initializer_list const&& ili) - { - using OnceIter = iter_stl::IterSnapshot; - return OnceIter(begin(ili), end(ili)); - } - - namespace {//Test fixture.... - - using DataSeq = vector; - - #define TOK(id) id(STRINGIFY(id)) - - string TOK(a1), TOK(a2), TOK(a3), TOK(a4), TOK(a5); - string TOK(b1), TOK(b2), TOK(b3), TOK(b4); - - using Interpreter = ListDiffInterpreter; - using DiffStep = ListDiffLanguage::DiffStep; - using DiffSeq = iter_stl::IterSnapshot; - - DiffStep_CTOR(ins); - DiffStep_CTOR(del); - DiffStep_CTOR(pick); - DiffStep_CTOR(push); - - - inline DiffSeq - generateTestDiff() - { - return snapshot({del(a1) - , del(a2) - , ins(b1) - , pick(a3) - , push(a5) - , pick(a5) - , ins(b2) - , ins(b3) - , pick(a4) - , ins(b4) - }); - - } - }//(End)Test fixture - - - - - - - - - - /***********************************************************************//** - * @test Demonstration/Concept: a description language for list differences. - * The representation is given as a linearised sequence of verb tokens. - * This test demonstrates the application of such a diff representation - * to a given source list, transforming this list to hold the intended - * target list contents. - * - * @see session-structure-mapping-test.cpp - */ - class DiffListApplication_test : public Test - { - - virtual void - run (Arg) - { - DataSeq src({a1,a2,a3,a4,a5}); - auto diff = generateTestDiff(); - CHECK (!isnil (diff)); - - DataSeq target = src; - DiffApplicator application(target); - application.consume(diff); - - CHECK (isnil (diff)); - CHECK (!isnil (target)); - CHECK (src != target); - CHECK (target == DataSeq({b1,a3,a5,b2,b3,a4,b4})); - } - }; - - - /** Register this test class... */ - LAUNCHER (DiffListApplication_test, "unit common"); - - - -}} // namespace lib::test +}} // namespace lib::diff +#endif /*LIB_DIFF_LIST_DIFF_H*/ diff --git a/src/lib/diff/tree-diff-application.hpp b/src/lib/diff/tree-diff-application.hpp index 360525949..b05f7e947 100644 --- a/src/lib/diff/tree-diff-application.hpp +++ b/src/lib/diff/tree-diff-application.hpp @@ -22,7 +22,10 @@ /** @file tree-diff-application.hpp - ** Fundamental definitions for a representation of changes. + ** Concrete implementation(s) to apply structural changes to hierarchical + ** data structures. Together with the generic #DiffApplicator, this allows + ** to receive linearised structural diff descriptions and apply them to + ** a given target data structure, to effect the correspoinding changes. ** ** @see diff-list-application-test.cpp ** @see VerbToken @@ -34,385 +37,18 @@ #define LIB_DIFF_TREE_DIFF_APPLICATION_H -#include "lib/test/run.hpp" -#include "lib/verb-token.hpp" -#include "lib/util.hpp" -#include "lib/iter-adapter-stl.hpp" -#include "lib/format-string.hpp" - -#include -#include -#include -#include -#include -#include - -using util::isnil; -using std::string; -using util::_Fmt; -using std::vector; -using std::move; - +#include "lib/diff/tree-diff.hpp" namespace lib { -namespace test{ - namespace error = lumiera::error; +namespace diff{ - LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected."); - - template< class I, typename E> - struct DiffLanguage - { - - using DiffVerb = VerbToken; - using VerbTok = std::tuple; - - struct DiffStep - : VerbTok - { - DiffVerb& verb() { return std::get<0>(*this); } - E elm() { return std::get<1>(*this); } - - DiffStep(DiffVerb verb, E e) - : VerbTok(verb,e) - { } - - operator string() const - { - return string(verb()) + "("+string(elm())+")"; - } - - void - applyTo (I& interpreter) - { - verb().applyTo (interpreter, elm()); - } - }; - }; - - template - using HandlerFun = void (I::*) (E); - - - template - struct DiffStepBuilder; - - /** generator to produce specific language tokens */ - template - struct DiffStepBuilder> - { - using Lang = DiffLanguage; - using Step = typename Lang::DiffStep; - using Verb = typename Lang::DiffVerb; - - HandlerFun handler; - Literal id; - - Step - operator() (E elm) const - { - return { Verb(handler,id), elm }; - } - }; - - - /** set up a diff language token generator, - * based on the specific handler function given. - * This generator will produce tokens, wrapping concrete content elements - * of type \c E. In the end, the purpose is to send a sequence of such tokens - * around, to feed them to a consumer, which implements the \em Interpreter - * interface of the diff language. E.g. this consumer might apply the diff. - */ - template - inline DiffStepBuilder - diffTokenBuilder (H handlerFun, Literal id) - { - return { handlerFun, id }; - } - -/** shortcut to define tokens of the diff language. - * Use it to define namespace level function objects, which, - * when supplied with an argument value of type \c E, will generate - * a specific language token wrapping a copy of this element. - * @note need a typedef \c Interpreter at usage site - * to refer to the actual language interpreter interface; - * the template parameters of the Language and the element - * type will be picked up from the given member function pointer. - */ -#define DiffStep_CTOR(_ID_) \ - const auto _ID_ = diffTokenBuilder (&Interpreter::_ID_, STRINGIFY(_ID_)); - - - template - class ListDiffInterpreter - { - public: - virtual ~ListDiffInterpreter() { } ///< this is an interface - - virtual void ins(E e) =0; - virtual void del(E e) =0; - virtual void pick(E e) =0; - virtual void push(E e) =0; - }; - - template - using ListDiffLanguage = DiffLanguage, E>; - - - - - - template - class DiffApplicationStrategy; - - /** - * concrete strategy to apply a list diff to a target sequence given as vector. - * The implementation swaps aside the existing content of the target sequence - * and then consumes it step by step, while building up the altered content - * within the previously emptied target vector. Whenever possible, elements - * are moved directly to the target location. - * @throws lumiera::error::State when diff application fails due to the - * target sequence being different than assumed by the given diff. - * @warning behaves only EX_SANE in case of diff application errors, - * i.e. only partially modified / rebuilt sequence might be - * in the target when diff application is aborted - */ template - class DiffApplicationStrategy> + class DiffApplicationStrategy> : public ListDiffInterpreter { - using Vec = vector; - using Iter = typename Vec::iterator; - Vec orig_; - Vec& seq_; - Iter pos_; - - bool - end_of_target() - { - return pos_ == orig_.end(); - } - - void - __expect_in_target (E const& elm, Literal oper) - { - if (end_of_target()) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "no (further) elements in target sequence") % oper % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - if (*pos_ != elm) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "found element %s on current target position instead") - % oper % elm % *pos_ - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_further_elements() - { - if (end_of_target()) - throw error::State("Premature end of target sequence; unable to apply diff further." - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_found (E const& elm, Iter const& targetPos) - { - if (targetPos == orig_.end()) - throw error::State(_Fmt("Premature end of sequence; unable to locate " - "element %s as reference point in target.") % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - - /* == Implementation of the diff application primitives == */ - - void - ins (E elm) - { - seq_.push_back(elm); - } - - void - del (E elm) - { - __expect_in_target(elm, "remove"); - ++pos_; - } - - void - pick (E elm) - { - __expect_in_target(elm, "pick"); - seq_.push_back (move(*pos_)); - ++pos_; - } - - void - push (E anchor) - { - __expect_further_elements(); - E elm(move(*pos_)); // consume current source element - ++pos_; - - // locate the insert position behind the given reference anchor - Iter insertPos = std::find(pos_, orig_.end(), anchor); - __expect_found (anchor, insertPos); - - // inserting the "pushed back" element behind the found position - // this might lead to reallocation and thus invalidate the iterators - auto currIdx = pos_ - orig_.begin(); - orig_.insert (++insertPos, move(elm)); - pos_ = orig_.begin() + currIdx; - } - - - public: - explicit - DiffApplicationStrategy(vector& targetVector) - : seq_(targetVector) - , pos_(seq_.begin()) - { - swap (seq_, orig_); // pos_ still refers to original input sequence, which has been moved to orig_ - seq_.reserve (targetVector.size() * 120 / 100); // heuristics for storage pre-allocation - } }; - /** - * generic builder to apply a list diff to a given target sequence. - * The usage pattern is as follows - * #. construct a DiffApplicator instance, wrapping the target sequence - * #. feed the list diff (sequence of diff verbs) to the #consume function - * #. the wrapped target sequence has been altered, to conform to the given diff - * @note a suitable DiffApplicationStrategy will be picked, based on the type - * of the concrete target sequence given at construction. (Effectively - * this means you need a suitable DiffApplicationStrategy specialisation, - * e.g. for a target sequence within a vector) - */ - template - class DiffApplicator - : boost::noncopyable - { - using Receiver = DiffApplicationStrategy; - - Receiver target_; - - public: - explicit - DiffApplicator(SEQ& targetSeq) - : target_(targetSeq) - { } - - template - void - consume (DIFF&& diff) - { - for ( ; diff; ++diff ) - diff->applyTo(target_); - } - }; - - namespace { - template - using ContentSnapshot = iter_stl::IterSnapshot; - } - - template - inline ContentSnapshot - snapshot(CON const& con) - { - return ContentSnapshot(begin(con), end(con)); - } - - template - inline iter_stl::IterSnapshot - snapshot(std::initializer_list const&& ili) - { - using OnceIter = iter_stl::IterSnapshot; - return OnceIter(begin(ili), end(ili)); - } - - namespace {//Test fixture.... - - using DataSeq = vector; - - #define TOK(id) id(STRINGIFY(id)) - - string TOK(a1), TOK(a2), TOK(a3), TOK(a4), TOK(a5); - string TOK(b1), TOK(b2), TOK(b3), TOK(b4); - - using Interpreter = ListDiffInterpreter; - using DiffStep = ListDiffLanguage::DiffStep; - using DiffSeq = iter_stl::IterSnapshot; - - DiffStep_CTOR(ins); - DiffStep_CTOR(del); - DiffStep_CTOR(pick); - DiffStep_CTOR(push); - - - inline DiffSeq - generateTestDiff() - { - return snapshot({del(a1) - , del(a2) - , ins(b1) - , pick(a3) - , push(a5) - , pick(a5) - , ins(b2) - , ins(b3) - , pick(a4) - , ins(b4) - }); - - } - }//(End)Test fixture - - - - - - - - - - /***********************************************************************//** - * @test Demonstration/Concept: a description language for list differences. - * The representation is given as a linearised sequence of verb tokens. - * This test demonstrates the application of such a diff representation - * to a given source list, transforming this list to hold the intended - * target list contents. - * - * @see session-structure-mapping-test.cpp - */ - class DiffListApplication_test : public Test - { - - virtual void - run (Arg) - { - DataSeq src({a1,a2,a3,a4,a5}); - auto diff = generateTestDiff(); - CHECK (!isnil (diff)); - - DataSeq target = src; - DiffApplicator application(target); - application.consume(diff); - - CHECK (isnil (diff)); - CHECK (!isnil (target)); - CHECK (src != target); - CHECK (target == DataSeq({b1,a3,a5,b2,b3,a4,b4})); - } - }; - - - /** Register this test class... */ - LAUNCHER (DiffListApplication_test, "unit common"); - - - -}} // namespace lib::test +}} // namespace lib::diff +#endif /*LIB_DIFF_TREE_DIFF_APPLICATION_H*/ diff --git a/src/lib/diff/tree-diff.hpp b/src/lib/diff/tree-diff.hpp index a2559919b..dbc86bf11 100644 --- a/src/lib/diff/tree-diff.hpp +++ b/src/lib/diff/tree-diff.hpp @@ -21,10 +21,17 @@ */ -/** @file tree-diff.hpp - ** Fundamental definitions for a representation of changes. +/** @file list-diff.hpp + ** A token language to represent structural changes in a tree like + ** hierarchical data structure. In combination with the #DiffLanguage framework, + ** this building block defines the set of operations to express both content + ** and structural changes in a given data structure. ** + ** @todo UNIMPLEMENTED as of 12/14 + ** + ** @see diff-language.cpp ** @see diff-list-application-test.cpp + ** @see list-diff.cpp ** @see VerbToken ** */ @@ -34,385 +41,34 @@ #define LIB_DIFF_TREE_DIFF_H -#include "lib/test/run.hpp" -#include "lib/verb-token.hpp" -#include "lib/util.hpp" -#include "lib/iter-adapter-stl.hpp" -#include "lib/format-string.hpp" - -#include -#include -#include -#include -#include -#include - -using util::isnil; -using std::string; -using util::_Fmt; -using std::vector; -using std::move; +#include "lib/diff/diff-language.hpp" namespace lib { -namespace test{ - namespace error = lumiera::error; - - LUMIERA_ERROR_DEFINE(DIFF_CONFLICT, "Collision in diff application: contents of target not as expected."); - - template< class I, typename E> - struct DiffLanguage - { - - using DiffVerb = VerbToken; - using VerbTok = std::tuple; - - struct DiffStep - : VerbTok - { - DiffVerb& verb() { return std::get<0>(*this); } - E elm() { return std::get<1>(*this); } - - DiffStep(DiffVerb verb, E e) - : VerbTok(verb,e) - { } - - operator string() const - { - return string(verb()) + "("+string(elm())+")"; - } - - void - applyTo (I& interpreter) - { - verb().applyTo (interpreter, elm()); - } - }; - }; - - template - using HandlerFun = void (I::*) (E); - - - template - struct DiffStepBuilder; - - /** generator to produce specific language tokens */ - template - struct DiffStepBuilder> - { - using Lang = DiffLanguage; - using Step = typename Lang::DiffStep; - using Verb = typename Lang::DiffVerb; - - HandlerFun handler; - Literal id; - - Step - operator() (E elm) const - { - return { Verb(handler,id), elm }; - } - }; - - - /** set up a diff language token generator, - * based on the specific handler function given. - * This generator will produce tokens, wrapping concrete content elements - * of type \c E. In the end, the purpose is to send a sequence of such tokens - * around, to feed them to a consumer, which implements the \em Interpreter - * interface of the diff language. E.g. this consumer might apply the diff. - */ - template - inline DiffStepBuilder - diffTokenBuilder (H handlerFun, Literal id) - { - return { handlerFun, id }; - } - -/** shortcut to define tokens of the diff language. - * Use it to define namespace level function objects, which, - * when supplied with an argument value of type \c E, will generate - * a specific language token wrapping a copy of this element. - * @note need a typedef \c Interpreter at usage site - * to refer to the actual language interpreter interface; - * the template parameters of the Language and the element - * type will be picked up from the given member function pointer. - */ -#define DiffStep_CTOR(_ID_) \ - const auto _ID_ = diffTokenBuilder (&Interpreter::_ID_, STRINGIFY(_ID_)); - - - template - class ListDiffInterpreter - { - public: - virtual ~ListDiffInterpreter() { } ///< this is an interface - - virtual void ins(E e) =0; - virtual void del(E e) =0; - virtual void pick(E e) =0; - virtual void push(E e) =0; - }; - - template - using ListDiffLanguage = DiffLanguage, E>; - - - - - - template - class DiffApplicationStrategy; - - /** - * concrete strategy to apply a list diff to a target sequence given as vector. - * The implementation swaps aside the existing content of the target sequence - * and then consumes it step by step, while building up the altered content - * within the previously emptied target vector. Whenever possible, elements - * are moved directly to the target location. - * @throws lumiera::error::State when diff application fails due to the - * target sequence being different than assumed by the given diff. - * @warning behaves only EX_SANE in case of diff application errors, - * i.e. only partially modified / rebuilt sequence might be - * in the target when diff application is aborted - */ - template - class DiffApplicationStrategy> - : public ListDiffInterpreter - { - using Vec = vector; - using Iter = typename Vec::iterator; - - Vec orig_; - Vec& seq_; - Iter pos_; - - bool - end_of_target() - { - return pos_ == orig_.end(); - } - - void - __expect_in_target (E const& elm, Literal oper) - { - if (end_of_target()) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "no (further) elements in target sequence") % oper % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - if (*pos_ != elm) - throw error::State(_Fmt("Unable to %s element %s from target as demanded; " - "found element %s on current target position instead") - % oper % elm % *pos_ - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_further_elements() - { - if (end_of_target()) - throw error::State("Premature end of target sequence; unable to apply diff further." - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - void - __expect_found (E const& elm, Iter const& targetPos) - { - if (targetPos == orig_.end()) - throw error::State(_Fmt("Premature end of sequence; unable to locate " - "element %s as reference point in target.") % elm - , LUMIERA_ERROR_DIFF_CONFLICT); - } - - - /* == Implementation of the diff application primitives == */ - - void - ins (E elm) - { - seq_.push_back(elm); - } - - void - del (E elm) - { - __expect_in_target(elm, "remove"); - ++pos_; - } - - void - pick (E elm) - { - __expect_in_target(elm, "pick"); - seq_.push_back (move(*pos_)); - ++pos_; - } - - void - push (E anchor) - { - __expect_further_elements(); - E elm(move(*pos_)); // consume current source element - ++pos_; - - // locate the insert position behind the given reference anchor - Iter insertPos = std::find(pos_, orig_.end(), anchor); - __expect_found (anchor, insertPos); - - // inserting the "pushed back" element behind the found position - // this might lead to reallocation and thus invalidate the iterators - auto currIdx = pos_ - orig_.begin(); - orig_.insert (++insertPos, move(elm)); - pos_ = orig_.begin() + currIdx; - } - - - public: - explicit - DiffApplicationStrategy(vector& targetVector) - : seq_(targetVector) - , pos_(seq_.begin()) - { - swap (seq_, orig_); // pos_ still refers to original input sequence, which has been moved to orig_ - seq_.reserve (targetVector.size() * 120 / 100); // heuristics for storage pre-allocation - } - }; +namespace diff{ /** - * generic builder to apply a list diff to a given target sequence. - * The usage pattern is as follows - * #. construct a DiffApplicator instance, wrapping the target sequence - * #. feed the list diff (sequence of diff verbs) to the #consume function - * #. the wrapped target sequence has been altered, to conform to the given diff - * @note a suitable DiffApplicationStrategy will be picked, based on the type - * of the concrete target sequence given at construction. (Effectively - * this means you need a suitable DiffApplicationStrategy specialisation, - * e.g. for a target sequence within a vector) + * Interpreter interface to define the operations ("verbs"), + * which describe differences or changes in hierarchical data structure. + * The meaning of the verbs is as follows: + * - \c TODO + * + * @todo to be defined */ - template - class DiffApplicator - : boost::noncopyable + template + class TreeDiffInterpreter { - using Receiver = DiffApplicationStrategy; - - Receiver target_; - public: - explicit - DiffApplicator(SEQ& targetSeq) - : target_(targetSeq) - { } - template - void - consume (DIFF&& diff) - { - for ( ; diff; ++diff ) - diff->applyTo(target_); - } + ///////TODO actual operations go here }; - namespace { - template - using ContentSnapshot = iter_stl::IterSnapshot; - } - - template - inline ContentSnapshot - snapshot(CON const& con) - { - return ContentSnapshot(begin(con), end(con)); - } - - template - inline iter_stl::IterSnapshot - snapshot(std::initializer_list const&& ili) - { - using OnceIter = iter_stl::IterSnapshot; - return OnceIter(begin(ili), end(ili)); - } - - namespace {//Test fixture.... - - using DataSeq = vector; - - #define TOK(id) id(STRINGIFY(id)) - - string TOK(a1), TOK(a2), TOK(a3), TOK(a4), TOK(a5); - string TOK(b1), TOK(b2), TOK(b3), TOK(b4); - - using Interpreter = ListDiffInterpreter; - using DiffStep = ListDiffLanguage::DiffStep; - using DiffSeq = iter_stl::IterSnapshot; - - DiffStep_CTOR(ins); - DiffStep_CTOR(del); - DiffStep_CTOR(pick); - DiffStep_CTOR(push); - - - inline DiffSeq - generateTestDiff() - { - return snapshot({del(a1) - , del(a2) - , ins(b1) - , pick(a3) - , push(a5) - , pick(a5) - , ins(b2) - , ins(b3) - , pick(a4) - , ins(b4) - }); - - } - }//(End)Test fixture + template + using TreeDiffLanguage = DiffLanguage, E>; - - - - - - /***********************************************************************//** - * @test Demonstration/Concept: a description language for list differences. - * The representation is given as a linearised sequence of verb tokens. - * This test demonstrates the application of such a diff representation - * to a given source list, transforming this list to hold the intended - * target list contents. - * - * @see session-structure-mapping-test.cpp - */ - class DiffListApplication_test : public Test - { - - virtual void - run (Arg) - { - DataSeq src({a1,a2,a3,a4,a5}); - auto diff = generateTestDiff(); - CHECK (!isnil (diff)); - - DataSeq target = src; - DiffApplicator application(target); - application.consume(diff); - - CHECK (isnil (diff)); - CHECK (!isnil (target)); - CHECK (src != target); - CHECK (target == DataSeq({b1,a3,a5,b2,b3,a4,b4})); - } - }; - - - /** Register this test class... */ - LAUNCHER (DiffListApplication_test, "unit common"); - - - -}} // namespace lib::test +}} // namespace lib::diff +#endif /*LIB_DIFF_TREE_DIFF_H*/ diff --git a/tests/library/diff-list-application-test.cpp b/tests/library/diff-list-application-test.cpp index 2e7516b23..d0b2668db 100644 --- a/tests/library/diff-list-application-test.cpp +++ b/tests/library/diff-list-application-test.cpp @@ -22,26 +22,21 @@ #include "lib/test/run.hpp" -#include "lib/verb-token.hpp" -#include "lib/util.hpp" +#include "lib/diff/list-diff-application.hpp" #include "lib/iter-adapter-stl.hpp" -#include "lib/format-string.hpp" +#include "lib/util.hpp" -#include -#include -#include #include #include -#include +using lib::iter_stl::snapshot; using util::isnil; using std::string; -using util::_Fmt; using std::vector; -using std::move; namespace lib { +namespace diff{ namespace test{ namespace {//Test fixture.... @@ -125,4 +120,4 @@ namespace test{ -}} // namespace lib::test +}}} // namespace lib::diff::test