C++自定义可对称双向迭代器

16 篇文章 0 订阅

#include <cassert>
#include <memory>
#include <vector>
#include <iostream>

class Range
{
public:
    using Index = uint64_t;
    using SignedIndex = int64_t;

    using Offset = int64_t;
    using Size = uint64_t;

    Range() = default;
    template <typename T>
    Range(T start, T end)
    {
        if (!isValidRange(start, end)) {
            assert(false);
            return;
        }
        m_start = start;
        m_end = end;
    }
    Range(const Range& other) = default;

    bool isEmpty() const { return 0 == size(); }

    bool isValid() const { return isValidRange(m_start, m_end); }

    bool isEqual(const Range& other) const { return m_start == other.m_start && m_end == other.m_end; }

    bool contains(SignedIndex pos) const { return pos >= 0 && contains((Index)pos); }

    bool contains(Index pos) const { return m_start <= pos && pos < m_end; }

    bool contains(const Range& other) const
    {
        return !other.isEmpty() && m_start <= other.m_start && other.m_end <= m_end;
    }
    Size size() const { return isValid() ? m_end - m_start : 0; }

    Index begin() const { return m_start; }
    Index start() const { return m_start; }

    Index end() const { return m_end; }

    Index last() const { return isEmpty() ? m_start : m_end - 1; }

    void setSize(Size newSize) { m_end = m_start + newSize; }
    bool operator==(const Range& other) const { return isEqual(other); }
    bool operator!=(const Range& other) const { return !isEqual(other); }
    friend std::ostream& operator<<(std::ostream& os, const Range& range)
    {
        os << "[" << range.m_start << "," << range.m_end << ")";
        return os;
    }

protected:
    template <typename T>
    static bool isValidRange(T start, T end)
    {
        return start >= 0 && end >= start;
    }

private:
    Index m_start = 0;
    Index m_end = 0;
};

class BidiRange : public Range
{
public:

    BidiRange::BidiRange(const Range& range, bool bForward) : Range(range), m_bForward(bForward) {}

    [[nodiscard]]  bool BidiRange::isForward() const
    {
        return m_bForward;
    }

private:
    bool m_bForward;
};


template <typename T>
class VisualIterator
{
public:
    using self = T;
    using reference = self&;
    using pointer = self*;
    constexpr explicit VisualIterator(T* ptr, size_t size) : m_node(ptr), m_size(size) {}
    constexpr reference            operator*() const { return *m_node; }
    constexpr pointer              operator->() const { return m_node; }
    constexpr virtual reference    operator++() = 0;
    constexpr virtual pointer      operator++(int size) = 0;
    constexpr virtual reference    operator--() = 0;
    constexpr virtual pointer      operator--(int size) = 0;
    [[nodiscard]] constexpr size_t size() const { return m_size; }
    constexpr size_t               operator-(const VisualIterator<T>& other) const { return m_node - other.operator->(); }

protected:
    pointer m_node;
    size_t  m_size;
};
template <typename T>
using VisualIteratorSp = typename std::shared_ptr<VisualIterator<T>>;

template <typename T>
class ForwardVisualIterator : public VisualIterator<T>
{
public:
    using reference = typename VisualIterator<T>::reference;
    using pointer = typename VisualIterator<T>::pointer;
    constexpr explicit ForwardVisualIterator(T* ptr, size_t size) : VisualIterator<T>(ptr, size) {}
    constexpr reference operator++() override
    {
        ++VisualIterator<T>::m_node;
        return *VisualIterator<T>::m_node;
    }
    constexpr pointer operator++(int size) override
    {
        pointer tmp = VisualIterator<T>::m_node;
        tmp += size;
        return tmp;
    }
    constexpr reference operator--() override
    {
        --VisualIterator<T>::m_node;
        return *VisualIterator<T>::m_node;
    }
    constexpr pointer operator--(int size) override
    {
        pointer tmp = VisualIterator<T>::m_node;
        tmp -= size;
        return tmp;
    }
};

template <typename T>
class ReverseVisualIterator : public VisualIterator<T>
{
public:
    using reference = typename VisualIterator<T>::reference;
    using pointer = typename VisualIterator<T>::pointer;
    constexpr explicit ReverseVisualIterator(T* ptr, size_t size) : VisualIterator<T>(ptr, size) {}
    constexpr reference operator++() override
    {
        --VisualIterator<T>::m_node;
        return *VisualIterator<T>::m_node;
    }
    constexpr pointer operator++(int size) override
    {
        pointer tmp = VisualIterator<T>::m_node;
        tmp -= size;
        return tmp;
    }
    constexpr reference operator--() override
    {
        ++VisualIterator<T>::m_node;
        return *VisualIterator<T>::m_node;
    }
    constexpr pointer operator--(int size) override
    {
        pointer tmp = VisualIterator<T>::m_node;
        tmp += size;
        return tmp;
    }
};

/*
template <typename T, template <typename> class VT>
VisualIteratorSp<T> makeVisualIterator(T *ptr, size_t size, bool bBegin)
{
    assert(false);
}
 */

template <typename T>
VisualIteratorSp<T> makeVisualIteratorForward(T* ptr, size_t size, bool bBegin)
{
    return std::make_shared<ForwardVisualIterator<T>>((bBegin ? ptr : ptr + size), size);
}

template <typename T>
VisualIteratorSp<T> makeVisualIteratorBack(T* ptr, size_t size, bool bBegin)
{
    return std::make_shared<ReverseVisualIterator<T>>((bBegin ? ptr + size - 1 : ptr - 1), size);
}

template <typename T>
class BidiVisualIterator
{
public:
    using self = T;
    using reference = self&;
    using pointer = self*;
    using BaseVisualIter = VisualIteratorSp<T>;
    constexpr explicit BidiVisualIterator(T* ptr, size_t size, bool dir, bool bBegin)
        : m_ltr(dir)
        , m_iter(dir ? makeVisualIteratorForward<T>(ptr, size, bBegin) : makeVisualIteratorBack<T>(ptr, size, bBegin))
    {
    }
    constexpr reference operator*() const { return m_iter->operator*(); }
    constexpr pointer   operator->() const { return m_iter->operator->(); }
    constexpr reference operator++() { return m_iter->operator++(); }
    constexpr pointer   operator++(int size) { return m_iter->operator++(size); }
    constexpr reference operator--() { return m_iter->operator--(); }
    constexpr pointer   operator--(int size) { return m_iter->operator--(size); }
    constexpr bool      operator==(const BidiVisualIterator<T>& other) const
    {
        return m_ltr == other.m_ltr && operator->() == other.operator->();
    }
    constexpr bool   operator!=(const BidiVisualIterator<T>& other) const { return !operator==(other); }
    constexpr size_t operator-(const BidiVisualIterator<T>& other) const
    {
        return (*m_iter).operator->() - other.operator->();
    }
    [[nodiscard]] constexpr bool isForward() const { return m_ltr; }

private:
    bool           m_ltr;
    BaseVisualIter m_iter;
};

/*
    支持内部双向迭代器rbegin,begin,rend,end
*/
template <typename T>
class BidiVisualSpan : public VisualIterator<T>
{
public:
    using reference = typename VisualIterator<T>::reference;
    using pointer = typename VisualIterator<T>::pointer;
    using cpointer = const typename VisualIterator<T>::self*;
    using pointerRef = typename VisualIterator<T>::self*&;
    constexpr explicit BidiVisualSpan(const T* ptr, const BidiRange& range)
        : VisualIterator<T>(const_cast<T*>(ptr), range.size())
        , m_bidiRange(range)
    {
    }
    constexpr BidiVisualIterator<T> begin() const
    {
        return BidiVisualIterator<T>(VisualIterator<T>::operator->(), VisualIterator<T>::size(), isForward(), true);
    }
    constexpr BidiVisualIterator<T> end() const
    {
        return BidiVisualIterator<T>(VisualIterator<T>::operator->(), VisualIterator<T>::size(), isForward(), false);
    }
    constexpr BidiVisualIterator<T> rbegin() const
    {
        return BidiVisualIterator<T>(VisualIterator<T>::operator->(), VisualIterator<T>::size(), !isForward(), true);
    }
    constexpr BidiVisualIterator<T> rend() const
    {
        return BidiVisualIterator<T>(VisualIterator<T>::operator->(), VisualIterator<T>::size(), !isForward(), false);
    }
    constexpr BidiVisualIterator<T> last() const
    {
        BidiVisualIterator<T> tmp = this->end();
        --tmp;
        return tmp;
    }
    constexpr pointer operator[](int i) const
    {
        BidiVisualIterator<T> tmp = this->begin();
        auto newNode = tmp.operator++(i);
        return newNode;
    }
    constexpr reference operator++()
    {
        VisualIterator<T>* base = this;
        return base->        operator*();
    }
    constexpr pointer operator++(int)
    {
        VisualIterator<T>* base = this;
        return base->        operator->();
    }
    constexpr reference operator--()
    {
        VisualIterator<T>* base = this;
        return base->        operator*();
    }
    constexpr pointer operator--(int)
    {
        VisualIterator<T>* base = this;
        return base->        operator->();
    }
    [[nodiscard]] constexpr bool               isForward() const { return m_bidiRange.isForward(); }
    [[nodiscard]] constexpr const BidiRange& getBidiRange() const { return m_bidiRange; }
    constexpr cpointer                inc(pointerRef data) const { return const_cast<T*>(isForward() ? ++data : --data); }
    constexpr cpointer                dec(pointerRef data) const { return const_cast<T*>(isForward() ? --data : ++data); }
    constexpr BidiVisualIterator<T> inc(const BidiVisualIterator<T>& data) const
    {
        auto tmp = data;
        ++tmp;
        return tmp;
    }
    constexpr BidiVisualIterator<T> dec(const BidiVisualIterator<T>& data) const
    {
        auto tmp = data;
        --tmp;
        return tmp;
    }

private:
    BidiRange m_bidiRange;
};



/**
 * @brief  双向迭代器测试
 * @return 支持正反序迭代
 */
bool testVisualSpan()
{
    std::vector<int> vcts{ 0, 1, 2, 3, 4, 5 };
    std::vector<int> expectVct;
    //    int *                 start = &vcts[0];
    BidiVisualSpan<int> spanVisual(&vcts[0], BidiRange(Range(0, 6), true));
    for (auto item = spanVisual.begin(); item != spanVisual.end(); ++item) {
        //        printf("%d\n", *item);
        expectVct.emplace_back(*item);
    }
    if (expectVct != vcts)
        return false;
    expectVct.clear();
    for (auto item : spanVisual) {
        //        printf("%d\n", item);
        expectVct.emplace_back(item);
    }
    if (expectVct != vcts)
        return false;
    expectVct.clear();
    for (auto item = spanVisual.rbegin(); item != spanVisual.rend(); ++item) {
        //        printf("%d\n", *item);
        expectVct.emplace_back(*item);
    }
    std::reverse(expectVct.begin(), expectVct.end());
    if (expectVct != vcts)
        return false;

    
    expectVct.clear();
    BidiVisualSpan<int> spanRVisual(&vcts[0], BidiRange(Range(0, 6), false));
    if (spanRVisual.rend() != spanVisual.end())
        return false;      // 支持双向同源迭代器
    if (spanRVisual.rbegin() != spanVisual.begin())
        return false;      // 支持双向同源迭代器
    for (auto item = spanRVisual.begin(); item != spanRVisual.end(); ++item) {
        //        printf("%d\n", *item);
        expectVct.emplace_back(*item);
    }
    std::reverse(expectVct.begin(), expectVct.end());
    if (expectVct != vcts)
        return false;
    expectVct.clear();
    for (auto item : spanRVisual) {
        //        printf("%d\n", item);
        expectVct.emplace_back(item);
    }
    std::reverse(expectVct.begin(), expectVct.end());
    if (expectVct != vcts)
        return false;
    expectVct.clear();
    for (auto item = spanRVisual.rbegin(); item != spanRVisual.rend(); ++item) {
        //        printf("%d\n", *item);
        expectVct.emplace_back(*item);
    }
    if (expectVct != vcts)
        return false;
    return true;
}

void test() {
    std::cout << (testVisualSpan() ? "Test OK !" : "Test Failed !") << std::endl; 
    // Test OK !
}

对比参考

std::bidirectional_iterator - cppreference.com


创作不易,小小的支持一下吧!

  • 19
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码力码力我爱你

创作不易,小小的支持一下吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值