complement IterStack by a similar wrapper for queue-like access
This commit is contained in:
parent
8ced6758fb
commit
2c33000346
4 changed files with 272 additions and 8 deletions
|
|
@ -20,6 +20,28 @@
|
|||
|
||||
*/
|
||||
|
||||
/** @file iter-stack.hpp
|
||||
** Conveniently iterable stack and queue containers.
|
||||
** Implemented as thin wrapper on top of std::deque
|
||||
** In addition to providing a simplified interface, these wrappers comply
|
||||
** to the "Lumiera Forward Iterator" concept, allowing to retrieve and discharge the
|
||||
** contents of the container in a standard fashion, especially by using util::for_each,
|
||||
** or by feeding them into a iterator based pipeline.
|
||||
**
|
||||
** @remarks contrary to the usual (STL) containers, this wrapper \em is an iterator
|
||||
** and a container at the same time. Which opens the interesting possibility
|
||||
** to intermix retrieval and feeding of new elements. It can be seen as a
|
||||
** zero overhead adapter to ease the use within Lumiera's library framework.
|
||||
** @note EX_STRONG, since std::deque gives this guarantee for push and pop operations
|
||||
** @warning STL containers aren't thread safe.
|
||||
**
|
||||
** @see IterStack_test
|
||||
** @see IterQueue_test
|
||||
** @see iter-adapter.hpp
|
||||
** @see itertools.hpp
|
||||
** @see IterSource (completely opaque iterator)
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_ITER_STACK_H
|
||||
|
|
@ -39,9 +61,10 @@ namespace lib {
|
|||
namespace {
|
||||
using util::unConst;
|
||||
|
||||
/**
|
||||
* Wrapper to mark a std::stack instance for use
|
||||
* as "state core" within lib::IterStateWrapper
|
||||
/**
|
||||
* Wrapper to mark a std::deque instance for use
|
||||
* as "state core" within lib::IterStateWrapper.
|
||||
* Iteration will pop elements from the back side.
|
||||
*/
|
||||
template<class TY>
|
||||
struct IterDequeStorage
|
||||
|
|
@ -75,7 +98,8 @@ namespace lib {
|
|||
|
||||
/**
|
||||
* A Stack which can be popped by iterating.
|
||||
* This is a simple helper built on top of std::stack.
|
||||
* This is a simple helper built by wrapping up
|
||||
* STL's double ended queue (deque).
|
||||
* 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.
|
||||
|
|
@ -91,22 +115,143 @@ namespace lib {
|
|||
|
||||
// using default create and copy operations
|
||||
|
||||
void
|
||||
IterStack&
|
||||
push (TY const& elm)
|
||||
{
|
||||
this->stateCore().push_back (elm);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TY
|
||||
pop()
|
||||
{
|
||||
this->__throw_if_empty();
|
||||
TY frontElement (this->stateCore().back());
|
||||
TY topElement (this->stateCore().back());
|
||||
this->stateCore().pop_back();
|
||||
return frontElement;
|
||||
return topElement;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A Queue which can be pulled by iterating.
|
||||
* As a variation of the IterStack frontend, here the
|
||||
* exposed additional interface works like a queue:
|
||||
* New elements can be fed, and the iteration will
|
||||
* consume the contents first-in first-out. The
|
||||
* implementation is based on std::deque, providing
|
||||
* both feed and the iterating operation in amortised
|
||||
* constant time, using chunk wise heap allocations.
|
||||
* Feeding of new elements into the queue and
|
||||
* retrieving old elements by iteration
|
||||
* may be mixed freely.
|
||||
*/
|
||||
template<class TY>
|
||||
struct IterQueue
|
||||
: IterStateWrapper<TY, IterDequeStorage<TY> >
|
||||
{
|
||||
|
||||
// using default create and copy operations
|
||||
|
||||
IterQueue&
|
||||
feed (TY const& elm)
|
||||
{
|
||||
this->stateCore().push_front (elm);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TY
|
||||
pop()
|
||||
{
|
||||
this->__throw_if_empty();
|
||||
TY firstElement (this->stateCore().back());
|
||||
this->stateCore().pop_back();
|
||||
return firstElement;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapter for use as opaque sequence.
|
||||
* This builder exposes generic operations
|
||||
* to prepare and pre-fill a sequence
|
||||
*/
|
||||
struct Builder
|
||||
{
|
||||
Builder() { }
|
||||
Builder(IterQueue const& initialElements)
|
||||
: queue_(initialElements)
|
||||
{ }
|
||||
// standard copy operations allowed
|
||||
|
||||
template<typename IT>
|
||||
IterQueue
|
||||
usingSequence (IT src)
|
||||
{
|
||||
for ( ; src; ++src )
|
||||
queue_.feed (*src);
|
||||
return queue_;
|
||||
}
|
||||
|
||||
private:
|
||||
IterQueue queue_;
|
||||
};
|
||||
|
||||
/** Extension point to be picked up by ADL.
|
||||
* The exposed Builder object allows client code
|
||||
* to prepare and pre-fill the queue, without
|
||||
* being tied to the implementation type
|
||||
* @param initial the initial contents of the queue
|
||||
* to start with, maybe empty. This parameter
|
||||
* also acts as type tag to pick this \c build()
|
||||
* function by ADL
|
||||
*/
|
||||
friend IterQueue::Builder
|
||||
build (IterQueue const& initial)
|
||||
{
|
||||
return Builder(initial);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** convenience free function to build an iterable sequence */
|
||||
template<typename T>
|
||||
inline IterQueue<T>
|
||||
elements (T const& elm)
|
||||
{
|
||||
return IterQueue<T>().feed(elm);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline IterQueue<T>
|
||||
elements (T const& e0, T const& e1)
|
||||
{
|
||||
return IterQueue<T>().feed(e0).feed(e1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline IterQueue<T>
|
||||
elements (T const& e0, T const& e1, T const& e2)
|
||||
{
|
||||
return IterQueue<T>().feed(e0).feed(e1).feed(e2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline IterQueue<T>
|
||||
elements (T const& e0, T const& e1, T const& e2, T const& e3)
|
||||
{
|
||||
return IterQueue<T>().feed(e0).feed(e1).feed(e2).feed(e3);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline IterQueue<T>
|
||||
elements (T const& e0, T const& e1, T const& e2, T const& e3, T const& e4)
|
||||
{
|
||||
return IterQueue<T>().feed(e0).feed(e1).feed(e2).feed(e3).feed(e4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -512,6 +512,10 @@ TEST "Stack-like iterator" IterStack_test
|
|||
END
|
||||
|
||||
|
||||
TEST "Queue-like iterator" IterQueue_test
|
||||
END
|
||||
|
||||
|
||||
TEST "Iterable type detection" IterableClassification_test <<END
|
||||
out: can_STL_ForEach<LongVector> : Yes
|
||||
out: can_STL_ForEach<TimeSet> : Yes
|
||||
|
|
|
|||
115
tests/lib/iter-queue-test.cpp
Normal file
115
tests/lib/iter-queue-test.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
IterQueue(Test) - verify queue-like iterator and builder function
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2012, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* @test cover an easy to use queue, built as convenience wrapper
|
||||
* on top of \c std::deque and allowing element retrieval
|
||||
* by iteration.
|
||||
* - iterable according to the Lumiera Forward Iterator concept
|
||||
* - can enqueue and dequeue elements repeatedly
|
||||
* - can be loaded through an generic builder API.
|
||||
*
|
||||
* @see IterExplorer
|
||||
* @see IterAdapter
|
||||
*/
|
||||
class IterQueue_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
IterQueue<int> queue;
|
||||
CHECK (isnil (queue));
|
||||
|
||||
VERIFY_ERROR (ITER_EXHAUST, *queue );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++queue );
|
||||
|
||||
queue.feed (1);
|
||||
queue.feed (3);
|
||||
queue.feed (5);
|
||||
|
||||
CHECK (!isnil (queue));
|
||||
CHECK (1 == *queue);
|
||||
|
||||
++queue;
|
||||
CHECK (3 == *queue);
|
||||
|
||||
CHECK (3 == queue.pop());
|
||||
CHECK (5 == *queue);
|
||||
|
||||
++queue;
|
||||
CHECK (isnil (queue));
|
||||
VERIFY_ERROR (ITER_EXHAUST, *queue );
|
||||
VERIFY_ERROR (ITER_EXHAUST, ++queue );
|
||||
VERIFY_ERROR (ITER_EXHAUST, queue.pop() );
|
||||
|
||||
|
||||
// use the generic builder API to feed
|
||||
// the contents of another iterator into the queue
|
||||
queue = build(queue).usingSequence (elements (23,45));
|
||||
|
||||
int i = queue.pop();
|
||||
CHECK (i == 23);
|
||||
CHECK (45 == *queue);
|
||||
|
||||
// feeding new elements and pulling / iteration can be mixed
|
||||
queue.feed(67);
|
||||
CHECK (45 == *queue);
|
||||
++queue;
|
||||
CHECK (67 == *queue);
|
||||
++queue;
|
||||
CHECK (isnil (queue));
|
||||
queue.feed(89);
|
||||
CHECK (89 == *queue);
|
||||
queue.pop();
|
||||
VERIFY_ERROR (ITER_EXHAUST, *queue );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
LAUNCHER (IterQueue_test, "unit common");
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
@ -47,7 +47,7 @@ namespace test{
|
|||
|
||||
/*********************************************************************
|
||||
* @test cover behaviour of a convenience class built by using a
|
||||
* std::stack as "state core" of an Lumiera IterStateWrapper.
|
||||
* \c std::deque 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
|
||||
|
|
|
|||
Loading…
Reference in a new issue