From f9c0c4c3d0c3d61e45abf7ca93095206f5ac4d89 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 6 Dec 2015 00:10:27 +0100 Subject: [PATCH] WIP: draft a direction switching iterator ...we need that to allow matching backwards in the EventLog --- src/lib/iter-cursor.hpp | 174 +++++++++++++++++ tests/library/iter-cursor-test.cpp | 288 +++++++++++++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 src/lib/iter-cursor.hpp create mode 100644 tests/library/iter-cursor-test.cpp diff --git a/src/lib/iter-cursor.hpp b/src/lib/iter-cursor.hpp new file mode 100644 index 000000000..938753ddd --- /dev/null +++ b/src/lib/iter-cursor.hpp @@ -0,0 +1,174 @@ +/* + ITER-CURSOR.hpp - wrap bidirectional STL container iterators + + Copyright (C) Lumiera.org + 2015, Hermann Vosseler + + This program 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file iter-cursor.hpp + ** An iterator with the ability to switch direction. + ** This wrapper relies on the ability of typical STL container iterators + ** to work in both directions, similar to std::reverse_iterator. + ** Yet it is a single, self-contained element and in compliance to the + ** ["Lumiera Forward Iterator"][iter-adapter.hpp] concept. But it has + ** the additional ability to [switch the working direction][IterCursor::switchDir]. + ** + ** @note as of 12/2015 this is complete bs + ** + ** @see IterCursor_test + ** @see iter-adapter.hpp + ** @see [usage example][event-log.hpp] + ** + */ + + +#ifndef SRC_LIB_ITER_CURSOR_H +#define SRC_LIB_ITER_CURSOR_H + + +#include "lib/error.hpp" +#include "lib/iter-adapter.hpp" +//#include "lib/symbol.hpp" +//#include "lib/util.hpp" + +//#include +//#include +#include + + +namespace lib { + namespace iter { + + /** + * @internal implementation for a "gear switching" iterator, + * based on STL container iterators. + */ + template + class CursorGear + { + bool backwards_{false}; + const IT start_; + const IT end_; + + IT pos_; + + + public: + typedef typename iter::TypeBinding::pointer pointer; + typedef typename iter::TypeBinding::reference reference; + typedef typename iter::TypeBinding::value_type value_type; + + + CursorGear() + : start_() + , end_() + , pos_() + { } + + CursorGear (IT&& begin, IT&& end) + : start_(std::forward(begin)) + , end_(std::forward(end)) + , pos_(start_) + { } + + // using default copy/assignment + + + void + toggle() + { + if (start_ == end_) return; + backwards_ = not backwards_; + ++pos_; + } + + /* === Iteration control API for IterStateWrapper == */ + + friend bool + checkPoint (CursorGear const& gear) + { + return gear.backwards_? gear.pos_ != gear.start_ + : gear.pos_ != gear.end_; + } + + friend reference + yield (CursorGear const& gear) + { + return gear.backwards_? *(gear.pos_-1) + : *(gear.pos_); + } + + friend void + iterNext (CursorGear & gear) + { + if (gear.backwards_) + --gear.pos_; + else + ++gear.pos_; + } + }; + + + } // namespace iter + + + + + /** + * A cursor-like iterator with the ability to switch iteration direction. + * + */ + template + class IterCursor + : public IterStateWrapper::reference, iter::CursorGear> + { + using _Core = IterStateWrapper::reference, iter::CursorGear>; + + public: + IterCursor() { } + + template + explicit + IterCursor (CON& container) + : _Core(container.begin(), container.end()) + { } + + IterCursor (IT&& begin, IT&& end) + : _Core(std::forward(begin), std::forward(end)) + { } + + + /** + * change the orientation of iteration. + * A forward oriented iteration will continue backwards, + * and vice versa. This operation can even be invoked + * on an already exhausted iterator, in which case + * it will turn back in reversed direction. + */ + IterCursor& + switchDir() + { + this->stateCore().toggle(); + return *this; + } + }; + + +} // namespace lib +#endif /*SRC_LIB_ITER_CURSOR_H*/ diff --git a/tests/library/iter-cursor-test.cpp b/tests/library/iter-cursor-test.cpp new file mode 100644 index 000000000..091995feb --- /dev/null +++ b/tests/library/iter-cursor-test.cpp @@ -0,0 +1,288 @@ +/* + IterCursor(Test) - verify operation of a iterator based navigation cursor + + Copyright (C) Lumiera.org + 2015, Hermann Vosseler + + This program 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/format-util.hpp" +#include "lib/iter-cursor.hpp" +#include "lib/util.hpp" + +#include + + + +namespace lib { +namespace test{ + + using ::Test; + using util::join; + using util::isnil; + using std::vector; + + using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; + + + namespace { // test fixture + + const uint NUM_ELMS = 10; + + using Numz = vector; + using Iter = IterCursor; + using CIter = IterCursor; + + inline Numz + makeNumz() + { + Numz numz; + for (uint i=0; i + void + verifyComparisons (IT const& ii) + { + IT i1(ii); + IT i2(ii); + IT iN; + CHECK ( isnil (iN)); + CHECK (!isnil (i1)); + CHECK (!isnil (i2)); + + CHECK (i1 == i2); CHECK (i2 == i1); + CHECK (i1 != iN); CHECK (iN != i1); + CHECK (i2 != iN); CHECK (iN != i2); + + ++i1; + CHECK (i1 != i2); + CHECK (i1 != iN); + + ++i2; + CHECK (i1 == i2); + CHECK (i1 != iN); + CHECK (i2 != iN); + + while (++i1) { } + CHECK (isnil(i1)); + CHECK (i1 != i2); + CHECK (i1 == iN); + + while (++i2) { } + CHECK (isnil(i2)); + CHECK (i2 == i1); + CHECK (i2 == iN); + } + }; + + LAUNCHER (IterCursor_test, "unit common"); + + +}} // namespace lib::test +