diff --git a/src/lib/iter-adapter.hpp b/src/lib/iter-adapter.hpp index 50e70aac4..c2ac2eafe 100644 --- a/src/lib/iter-adapter.hpp +++ b/src/lib/iter-adapter.hpp @@ -303,21 +303,21 @@ namespace lib { reference operator*() const { - _maybe_throw(); + __throw_if_empty(); return yield (core_); // extension point: yield } pointer operator->() const { - _maybe_throw(); + __throw_if_empty(); return & yield(core_); // extension point: yield } IterStateWrapper& operator++() { - _maybe_throw(); + __throw_if_empty(); iterNext (core_); // extension point: iterNext return *this; } @@ -334,10 +334,18 @@ namespace lib { return !isValid(); } - private: + protected: + + /** allow derived classes to + * access state representation */ + ST & + stateCore() + { + return core_; + } void - _maybe_throw() const + __throw_if_empty() const { if (!isValid()) _throwIterExhausted(); diff --git a/src/lib/iter-stack.hpp b/src/lib/iter-stack.hpp new file mode 100644 index 000000000..607f43bf2 --- /dev/null +++ b/src/lib/iter-stack.hpp @@ -0,0 +1,111 @@ +/* + ITER-STACK.hpp - a stack which can be popped by iterating + + Copyright (C) Lumiera.org + 2012, 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. + +*/ + + + +#ifndef LIB_ITER_STACK_H +#define LIB_ITER_STACK_H + + +#include "lib/error.hpp" +#include "lib/iter-adapter.hpp" +#include "lib/util.hpp" + +#include + + +namespace lib { + + + namespace { + using util::unConst; + + /** + * Wrapper to mark a std::stack instance for use + * as "state core" within lib::IterStateWrapper + */ + template + struct IterStackStorage + : std::stack + { + /* === Iteration control API for IterStateWrapper == */ + + friend bool + checkPoint (IterStackStorage const& elements) + { + return !elements.empty(); + } + + friend TY & + yield (IterStackStorage const& elements) + { + return unConst(elements).top(); + } + + friend void + iterNext (IterStackStorage & elements) + { + REQUIRE (!elements.empty()); + elements.pop(); + } + }; + }//(End) Wrapper/Helper + + + + /** + * A Stack which can be popped by iterating. + * This is a simple helper built on top of std::stack. + * Thus, each instance holds the full state, which is + * actually kept in heap allocated storage. Pushing of + * new elements and iterator use may be mixed. + * + * Contrary to just using std::stack + * - the iteration is compliant to the Lumiera Forward Iterator concept + * - there is a simplified #pop() function which removes and returns at once + */ + template + struct IterStack + : IterStateWrapper > + { + + // using default create and copy operations + + void + push (TY const& elm) + { + this->stateCore().push (elm); + } + + TY + pop() + { + this->__throw_if_empty(); + TY frontElement (this->stateCore().top()); + this->stateCore().pop(); + return frontElement; + } + }; + + +} // namespace lib +#endif diff --git a/tests/40components.tests b/tests/40components.tests index ca790c658..3b901d8d3 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -508,6 +508,10 @@ out: values_4_key(::[0-9]{1,2})+ END +TEST "Stack-like iterator" IterStack_test +END + + TEST "Iterable type detection" IterableClassification_test < : Yes out: can_STL_ForEach : Yes diff --git a/tests/lib/iter-stack-test.cpp b/tests/lib/iter-stack-test.cpp new file mode 100644 index 000000000..82d93b4b5 --- /dev/null +++ b/tests/lib/iter-stack-test.cpp @@ -0,0 +1,111 @@ +/* + IterStack(Test) - verify stack-like iterator + + Copyright (C) Lumiera.org + 2012, 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/util.hpp" + +#include "lib/iter-stack.hpp" + + + +namespace lib { +namespace test{ + + using ::Test; + using util::isnil; + using lumiera::error::LUMIERA_ERROR_ITER_EXHAUST; + + + + + typedef IterStack IStack; + + + + + /********************************************************************* + * @test cover behaviour of a convenience class built by using a + * std::stack as "state core" of an Lumiera IterStateWrapper. + * - iterable according to the Lumiera Forward Iterator concept + * - can push and pop values repeatedly + * - iterating and push / pop can be mixed + * - empty state detected consistently + * + * @see IterExplorer + * @see IterAdapter + */ + class IterStack_test : public Test + { + + virtual void + run (Arg) + { + IStack stack; + CHECK (isnil (stack)); + + VERIFY_ERROR (ITER_EXHAUST, *stack ); + VERIFY_ERROR (ITER_EXHAUST, ++stack ); + + stack.push (1); + stack.push (3); + stack.push (5); + stack.push (7); + stack.push (9); + + CHECK (!isnil (stack)); + CHECK (9 == *stack); + + ++stack; + CHECK (7 == *stack); + + CHECK (7 == stack.pop()); + CHECK (5 == *stack); + + ++++stack; + CHECK (1 == *stack); + CHECK (1 == stack.pop()); + + CHECK (isnil (stack)); + VERIFY_ERROR (ITER_EXHAUST, *stack ); + VERIFY_ERROR (ITER_EXHAUST, ++stack ); + VERIFY_ERROR (ITER_EXHAUST, stack.pop() ); + + + stack.push(23); + CHECK (23 == *stack); + + int i = stack.pop(); + CHECK (i == 23); + VERIFY_ERROR (ITER_EXHAUST, *stack ); + CHECK (isnil (stack)); + } + + }; + + + LAUNCHER (IterStack_test, "unit common"); + + +}} // namespace lib::test