blob: 19e9d20976df0e34c04d1997e8057a71c2db2541 (
plain) (
tree)
|
|
#pragma once
#include <iterator>
#include <utility>
namespace NStlIterator {
template <class T>
class TProxy {
public:
TProxy() = default;
TProxy(T&& value)
: Value_(std::move(value))
{
}
const T* operator->() const noexcept {
return &Value_;
}
const T& operator*() const noexcept {
return Value_;
}
bool operator==(const TProxy& rhs) const {
return Value_ == rhs.Value_;
}
private:
T Value_;
};
} // namespace NStlIterator
/**
* Range adaptor that turns a derived class with a Java-style iteration
* interface into an STL range.
*
* Derived class is expected to define:
* \code
* TSomething* Next();
* \endcode
*
* `Next()` returning `nullptr` signals end of range. Note that you can also use
* pointer-like types instead of actual pointers (e.g. `TAtomicSharedPtr`).
*
* Since iteration state is stored inside the derived class, the resulting range
* is an input range (works for single pass algorithms only). Technically speaking,
* if you're returning a non-const pointer from `Next`, it can also work as an output range.
*
* Example usage:
* \code
* class TSquaresGenerator: public TInputRangeAdaptor<TSquaresGenerator> {
* public:
* const double* Next() {
* Current_ = State_ * State_;
* State_ += 1.0;
* // Never return nullptr => we have infinite range!
* return &Current_;
* }
*
* private:
* double State_ = 0.0;
* double Current_ = 0.0;
* }
* \endcode
*/
template <class TSlave>
class TInputRangeAdaptor {
public: // TODO: private
class TIterator {
public:
static constexpr bool IsNoexceptNext = noexcept(std::declval<TSlave>().Next());
using difference_type = std::ptrdiff_t;
using pointer = decltype(std::declval<TSlave>().Next());
using reference = decltype(*std::declval<TSlave>().Next());
using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
using iterator_category = std::input_iterator_tag;
inline TIterator() noexcept
: Slave_(nullptr)
, Cur_()
{
}
inline TIterator(TSlave* slave) noexcept(IsNoexceptNext)
: Slave_(slave)
, Cur_(Slave_->Next())
{
}
inline bool operator==(const TIterator& it) const noexcept {
return Cur_ == it.Cur_;
}
inline bool operator!=(const TIterator& it) const noexcept {
return !(*this == it);
}
inline pointer operator->() const noexcept {
return Cur_;
}
inline reference operator*() const noexcept {
return *Cur_;
}
inline TIterator& operator++() noexcept(IsNoexceptNext) {
Cur_ = Slave_->Next();
return *this;
}
private:
TSlave* Slave_;
pointer Cur_;
};
public:
using const_iterator = TIterator;
using iterator = const_iterator;
inline iterator begin() const noexcept(TIterator::IsNoexceptNext) {
return TIterator(const_cast<TSlave*>(static_cast<const TSlave*>(this)));
}
inline iterator end() const noexcept {
return TIterator();
}
};
/**
* Transform given reverse iterator into forward iterator pointing to the same element.
*
* @see http://stackoverflow.com/a/1830240
*/
template <class TIterator>
auto ToForwardIterator(TIterator iter) {
return std::next(iter).base();
}
|