2012-06-04 01:08:58 +02:00
|
|
|
|
/*
|
2025-06-07 23:59:57 +02:00
|
|
|
|
ITER-STACK.hpp - a stack which can be popped by iterating
|
2012-06-04 01:08:58 +02: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)
|
|
|
|
|
|
2012, Hermann Vosseler <Ichthyostega@web.de>
|
2012-06-04 01:08:58 +02: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.
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
/** @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.
|
|
|
|
|
|
**
|
2012-07-12 03:21:47 +02:00
|
|
|
|
** \par the builder extension point
|
|
|
|
|
|
** while Lumiera Forward Iterators only allow to retrieve some elements once,
|
|
|
|
|
|
** the special extension point \c build(sequence) allows abstracted access to some
|
|
|
|
|
|
** limited manipulation of the sequence, without tying the client to a specific
|
|
|
|
|
|
** sequence or iterator implementation. This is intended for library templates,
|
|
|
|
|
|
** which typically can't make any assumptions regarding the iterator types
|
|
|
|
|
|
** used for instantiation.
|
|
|
|
|
|
**
|
2012-06-25 05:00:56 +02:00
|
|
|
|
** @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.
|
2025-06-07 23:59:57 +02:00
|
|
|
|
** @note EX_STRONG, since std::deque gives this guarantee for push and pop operations
|
|
|
|
|
|
** @warning STL containers aren't thread safe.
|
2012-06-25 05:00:56 +02:00
|
|
|
|
**
|
|
|
|
|
|
** @see IterStack_test
|
|
|
|
|
|
** @see IterQueue_test
|
|
|
|
|
|
** @see iter-adapter.hpp
|
|
|
|
|
|
** @see itertools.hpp
|
|
|
|
|
|
** @see IterSource (completely opaque iterator)
|
|
|
|
|
|
**
|
|
|
|
|
|
*/
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_ITER_STACK_H
|
|
|
|
|
|
#define LIB_ITER_STACK_H
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
|
|
|
|
|
#include "lib/iter-adapter.hpp"
|
2012-07-12 03:00:12 +02:00
|
|
|
|
#include "lib/nocopy.hpp"
|
2012-06-04 01:08:58 +02:00
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
2012-06-24 19:28:19 +02:00
|
|
|
|
#include <deque>
|
2017-04-16 18:27:05 +02:00
|
|
|
|
#include <utility>
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
|
2017-08-05 17:57:25 +02:00
|
|
|
|
using util::unConst;
|
|
|
|
|
|
|
2016-12-25 20:09:24 +01:00
|
|
|
|
namespace iter {
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
/**
|
|
|
|
|
|
* Wrapper to mark a std::deque instance for use
|
|
|
|
|
|
* as "state core" within lib::IterStateWrapper.
|
|
|
|
|
|
* Iteration will pop elements from the back side.
|
2012-06-04 01:08:58 +02:00
|
|
|
|
*/
|
|
|
|
|
|
template<class TY>
|
2012-06-24 19:28:19 +02:00
|
|
|
|
struct IterDequeStorage
|
|
|
|
|
|
: std::deque<TY>
|
2012-06-04 01:08:58 +02:00
|
|
|
|
{
|
|
|
|
|
|
/* === Iteration control API for IterStateWrapper == */
|
|
|
|
|
|
|
2017-12-05 03:28:00 +01:00
|
|
|
|
bool
|
|
|
|
|
|
checkPoint() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return not this->empty();
|
|
|
|
|
|
}
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
2017-12-05 03:28:00 +01:00
|
|
|
|
TY &
|
|
|
|
|
|
yield() const
|
|
|
|
|
|
{
|
|
|
|
|
|
REQUIRE (not this->empty());
|
|
|
|
|
|
return unConst(this)->back();
|
|
|
|
|
|
}
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
2017-12-05 03:28:00 +01:00
|
|
|
|
void
|
|
|
|
|
|
iterNext()
|
|
|
|
|
|
{
|
|
|
|
|
|
REQUIRE (not this->empty());
|
|
|
|
|
|
this->pop_back();
|
|
|
|
|
|
}
|
2012-06-04 01:08:58 +02:00
|
|
|
|
};
|
2016-12-25 20:09:24 +01:00
|
|
|
|
} // namespace lib::iter
|
2012-06-04 01:08:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* A Stack which can be popped by iterating.
|
2012-06-25 05:00:56 +02:00
|
|
|
|
* This is a simple helper built by wrapping up
|
|
|
|
|
|
* STL's double ended queue (deque).
|
2012-06-04 01:08:58 +02:00
|
|
|
|
* 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<class TY>
|
|
|
|
|
|
struct IterStack
|
2024-11-26 22:15:33 +01:00
|
|
|
|
: IterStateWrapper<iter::IterDequeStorage<TY>>
|
2012-06-04 01:08:58 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// using default create and copy operations
|
|
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
IterStack&
|
2012-06-04 01:08:58 +02:00
|
|
|
|
push (TY const& elm)
|
|
|
|
|
|
{
|
2012-06-24 19:28:19 +02:00
|
|
|
|
this->stateCore().push_back (elm);
|
2012-06-25 05:00:56 +02:00
|
|
|
|
return *this;
|
2012-06-04 01:08:58 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-16 16:16:26 +02:00
|
|
|
|
IterStack&
|
2017-04-16 18:27:05 +02:00
|
|
|
|
push (TY&& elm)
|
2017-04-16 16:16:26 +02:00
|
|
|
|
{
|
2017-04-16 18:27:05 +02:00
|
|
|
|
this->stateCore().emplace_back (std::move (elm));
|
2017-04-16 16:16:26 +02:00
|
|
|
|
return *this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-27 02:50:36 +02:00
|
|
|
|
IterStack&
|
|
|
|
|
|
insert (TY const& elm)
|
|
|
|
|
|
{
|
|
|
|
|
|
return push(elm);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-04 01:08:58 +02:00
|
|
|
|
TY
|
|
|
|
|
|
pop()
|
|
|
|
|
|
{
|
|
|
|
|
|
this->__throw_if_empty();
|
2017-08-07 00:20:55 +02:00
|
|
|
|
TY topElement (std::move (this->stateCore().back()));
|
2012-06-24 19:28:19 +02:00
|
|
|
|
this->stateCore().pop_back();
|
2012-06-25 05:00:56 +02:00
|
|
|
|
return topElement;
|
2012-06-04 01:08:58 +02:00
|
|
|
|
}
|
2017-08-05 17:57:25 +02:00
|
|
|
|
|
2018-09-12 03:52:07 +02:00
|
|
|
|
void
|
|
|
|
|
|
clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
this->stateCore().clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-08-05 17:57:25 +02:00
|
|
|
|
|
|
|
|
|
|
/* == diagnostics == */
|
|
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
|
size() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return unConst(this)->stateCore().size();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
empty() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0 == size();
|
|
|
|
|
|
}
|
2012-06-04 01:08:58 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
|
|
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
/**
|
2012-06-25 05:00:56 +02:00
|
|
|
|
* 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
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* retrieving old elements by iteration
|
2012-06-25 05:00:56 +02:00
|
|
|
|
* may be mixed freely.
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<class TY>
|
|
|
|
|
|
struct IterQueue
|
2024-11-26 22:15:33 +01:00
|
|
|
|
: IterStateWrapper<iter::IterDequeStorage<TY>>
|
2012-06-25 05:00:56 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// using default create and copy operations
|
|
|
|
|
|
|
|
|
|
|
|
IterQueue&
|
|
|
|
|
|
feed (TY const& elm)
|
|
|
|
|
|
{
|
|
|
|
|
|
this->stateCore().push_front (elm);
|
|
|
|
|
|
return *this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-04-16 16:16:26 +02:00
|
|
|
|
IterQueue&
|
2017-04-16 18:27:05 +02:00
|
|
|
|
feed (TY&& elm)
|
2017-04-16 16:16:26 +02:00
|
|
|
|
{
|
2017-04-16 18:27:05 +02:00
|
|
|
|
this->stateCore().emplace_front (std::move (elm));
|
2017-04-16 16:16:26 +02:00
|
|
|
|
return *this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-27 02:50:36 +02:00
|
|
|
|
IterQueue&
|
|
|
|
|
|
insert (TY const& elm)
|
|
|
|
|
|
{
|
|
|
|
|
|
return feed(elm);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
TY
|
|
|
|
|
|
pop()
|
|
|
|
|
|
{
|
|
|
|
|
|
this->__throw_if_empty();
|
2017-08-07 00:20:55 +02:00
|
|
|
|
TY firstElement (std::move (this->stateCore().back()));
|
2012-06-25 05:00:56 +02:00
|
|
|
|
this->stateCore().pop_back();
|
|
|
|
|
|
return firstElement;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-08-05 17:57:25 +02:00
|
|
|
|
/* == diagnostics == */
|
|
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
|
size() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return unConst(this)->stateCore().size();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
empty() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0 == size();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-06-07 23:59:57 +02:00
|
|
|
|
/**
|
2012-06-25 05:00:56 +02:00
|
|
|
|
* Adapter for use as opaque sequence.
|
|
|
|
|
|
* This builder exposes generic operations
|
|
|
|
|
|
* to prepare and pre-fill a sequence
|
|
|
|
|
|
*/
|
|
|
|
|
|
struct Builder
|
Invocation: develop a concept for handling parameter data
...as part of the rendering process, executed on top of the
low-level-model (Render Node network) as conceived thus far.
Parameter handling could be ''encoded'' into render nodes altogether,
or, at the other extreme, an explicit parameter handling could be specified
as part of the Render Node execution. As both extremes will lead to some
unfavourable consequences, I am aiming at a middle ground: largely, the
''automation computation'' will be encoded and hidden within the network,
implying that this topic remains to be addressed as part of defining
the Builder semantics and implementation. Yet in part the required
processing structure can be foreseen at an abstract level, and thus
the essential primitive operations are specified explicitly as part
of the Render Node definition. Notably the ''standard Weaving Pattern''
will include a ''parameter tuple'' into each `FeedManifold` and require
a binding function, which accepts this tuple as first argument.
Moreover — at implementation level, a library facility must be provided
to support handling of ''arbitrary heterogeneous data values'' embedded
directly into stack frame memory, together with a type-safe compile-time
overlay, which allows the builder to embed specific ''accessor handles''
into functor bindings, even while the actual storage location is not
yet known at that time (obviously, as being located on the stack).
__Note__: a recurring topic is how to return descriptor objects from builder functions; for this purpose, I am adjusting the semantics of `lib/nocopy.hpp` to be more specific...
2024-12-09 21:55:48 +01:00
|
|
|
|
: util::NonCopyable
|
2012-06-25 05:00:56 +02:00
|
|
|
|
{
|
2012-07-12 03:21:47 +02:00
|
|
|
|
Builder(IterQueue& initialElements)
|
2012-06-25 05:00:56 +02:00
|
|
|
|
: queue_(initialElements)
|
|
|
|
|
|
{ }
|
|
|
|
|
|
// standard copy operations allowed
|
|
|
|
|
|
|
|
|
|
|
|
template<typename IT>
|
2012-07-12 03:21:47 +02:00
|
|
|
|
IterQueue &
|
2012-06-25 05:00:56 +02:00
|
|
|
|
usingSequence (IT src)
|
|
|
|
|
|
{
|
|
|
|
|
|
for ( ; src; ++src )
|
|
|
|
|
|
queue_.feed (*src);
|
|
|
|
|
|
return queue_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-07-12 03:21:47 +02:00
|
|
|
|
IterQueue &
|
|
|
|
|
|
wrapping (TY const& elm)
|
2012-07-01 03:42:50 +02:00
|
|
|
|
{
|
|
|
|
|
|
queue_.feed (elm);
|
|
|
|
|
|
return queue_;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2012-06-25 05:00:56 +02:00
|
|
|
|
private:
|
2012-07-12 03:21:47 +02:00
|
|
|
|
IterQueue& queue_;
|
2012-06-25 05:00:56 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** 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()
|
2025-06-07 23:59:57 +02:00
|
|
|
|
* function by ADL
|
2012-06-25 05:00:56 +02:00
|
|
|
|
*/
|
|
|
|
|
|
friend IterQueue::Builder
|
2012-07-12 03:21:47 +02:00
|
|
|
|
build (IterQueue& initial)
|
2012-06-25 05:00:56 +02:00
|
|
|
|
{
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-04 01:08:58 +02:00
|
|
|
|
} // namespace lib
|
|
|
|
|
|
#endif
|