LUMIERA.clone/src/lib/iter-index.hpp
2024-03-25 00:37:58 +01:00

155 lines
4.9 KiB
C++

/*
ITER-INDEX.hpp - iterator with indexed random-access to referred container
Copyright (C) Lumiera.org
2024, 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.
*/
/** @file iter-index.hpp
** Iterator-style access handle to a referred container with subscript index.
** This wrapper packages a current index number and a back-link to some data container
** with subscript operator and range check. This allows to hand out a navigable access point
** to a processing algorithm while abstracting away the actual data storage. Besides usage
** as »Lumiera Forward Iterator«, the current access position can be retrieved directly
** and it can be relocated to another valid index position; this implies also the ability
** to re-set the iteration to the container's start. Optionally, a smart-ptr can be
** embedded, allowing the handle also to owns and manage the data container.
**
** @see IterIndex_test
** @see iter-adapter.hpp
** @see [usage example](\ref lib::TextTemplate::InstanceCore)
*/
#ifndef SRC_LIB_ITER_INDEX_H
#define SRC_LIB_ITER_INDEX_H
#include "lib/iter-adapter.hpp"
namespace lib {
namespace iter {
/**
* Implementation of a »IterStateCore«
* to access the container through an embedded index variable.
*/
template<typename PTR>
struct IndexAccessCore
{
PTR data_{};
size_t idx_{0};
using ResVal = decltype(data_->operator[](0));
using value_type = typename meta::RefTraits<ResVal>::Value;
using reference = typename meta::RefTraits<ResVal>::Reference;
using IterWrapper = lib::IterStateWrapper<value_type, IndexAccessCore>;
bool
checkPoint() const
{
return isValidIDX(idx_);
}
reference
yield() const
{
return (*data_)[idx_];
}
void
iterNext()
{
++idx_;
}
bool
isValidIDX (size_t idx) const
{
return bool(data_)
and idx < data_->size();
}
friend bool operator== (IndexAccessCore const& c1, IndexAccessCore const& c2)
{
return c1.data_ == c2.data_ and (not c1.data_ or c1.idx_ == c2.idx_);
}
friend bool operator!= (IndexAccessCore const& c1, IndexAccessCore const& c2)
{
return not (c1 == c2);
}
};
//
}//(End)Implementation
/**
* Subscript-index based access to a container, packaged as iterator.
* This is a copyable and assignable value object (handle), referring to some
* data container maintained elsewhere. The container must provide an `operator[]`.
* This handle can be used as »Lumiera Forward Iterator«, but with the additional
* capability to retrieve and re-set the current index position.
* @tparam CON a container with `operator[]` and a function `size()`
* @tparam PTR how to refer to this container; can be defined as smart-ptr,
* additionally allowing to manage this container automatically.
* @remark while a default constructed IterIndex and some _exhausted_ IterIndex
* compare equal, only the latter can be re-set into active state.
*/
template<class CON, typename PTR = CON*>
class IterIndex
: public iter::IndexAccessCore<PTR>::IterWrapper
{
using _Cor = iter::IndexAccessCore<PTR>;
using _Par = typename _Cor::IterWrapper;
public:
IterIndex() = default;
IterIndex (CON& container) : IterIndex{&container}{ };
IterIndex (PTR pContainer)
: _Par{_Cor{pContainer, 0}}
{ }
size_t
getIDX() const
{
_Par::__throw_if_empty();
return _Par::stateCore().idx_;
}
void
setIDX (size_t newIDX)
{
auto& core = _Par::stateCore();
if (not core.isValidIDX (newIDX))
throw lumiera::error::Invalid ("Attempt to set index out of bounds",
lumiera::error::LUMIERA_ERROR_INDEX_BOUNDS);
core.idx_ = newIDX;
}
};
} // namespace lib
#endif /*SRC_LIB_ITER_INDEX_H*/