替换" FOR()"循环缓冲区/ fifo队列数组元素中的宏

时间:2014-12-19 20:09:01

标签: c++ performance for-loop c-preprocessor fifo

我有以下方式实现的Elem结构的FIFO:

直到达到max_elems限制Push()只是将给定元素放在数组中的最后一个元素之后并递增elems(count)。 如果elems已经达到max_elems,它会通过提前头索引来模拟pop,因此它的行为类似于循环缓冲区。

struct FIFO
{
    FIFO(int mx)
    {
        head = 0;
        elems = 0;
        max_elems = mx;
        elem = new Elem[max_elems]; 
    }

    int elems;
    int max_elems;

    Elem* elem; // [max_elems]

    int head;

    void Push( const Elem* e )
    {
        // int i = (elems+head) % max_elems;

        int i = elems + head;
        if (i >= max_elems)
            i -= max_elems;

        elem[ i ] = *e;

        if (elems < max_elems)
            elems ++;
        else
        {
            head ++;
            if (head == max_elems)
                head = 0;
        }
    }

    Elem* GetItem(int i)
    {
        // int j = (i+head)%max_elems;

        int j = i + head;
        if (j >= max_elems)
            j -= max_elems;

        return elem + j;
    }
};

我需要迭代elem数组中的元素。我迫切希望将性能保持在MAX。 因此,我没有在常规for()中使用GetItem,而是创建了一个FOR宏:

#define FOR(fifo,elem,from,count,code) \
if (fifo->head==0) \
{ \
    int to = from+count;
    for (int i = from; i<to; i++) \
    { \
        Elem* elem = fifo->elem+i; \
        code \
    } \
else \
{ \
    int f = from+fifo->head; \
    if (f>=fifo->max_elems) \
        f-=fifo->max_elems; \
    int to = min(f + count, fifo->max_elems); \
    for (int i = f; i<to; i++) \
    { \
        Elem* elem = fifo->elem+i; \
        code \
    } \
    to = count - (to-f); \
    for (int i = 0; i<to; i++) \
    { \
        Elem* elem = fifo->elem+i; \
        code \
    } \
}

这是我可以使用它的方式

void main()
{
    FIFO buf(10000);
    Elem e;

    buf.Push(&e);
    buf.Push(&e);
    // ...

    FOR (  buf, pe , 11, 5009, { pe->do_something(); } );
}

我讨厌这个宏,因为无法调试代码&#39;内联其中。

最后我的问题是:

有没有更优雅的方式来制作这样的&#39; FOR&#39;但不是宏观?

2 个答案:

答案 0 :(得分:3)

c ++方法是用模板函数替换这样的可怕宏,模板函数可以调试(和测试)。

编辑:根据要求,这是第一次尝试用函数替换宏。实际上不需要模板 - std :: function(可以从lambda初始化)就足够了:

void for_elems_in_fifo(FIFO* fifo,int from,int count,std::function<void(Elem&)> code)
{
    if (fifo->head==0)
    {
        int to = from+count;
        for (int i = from; i<to; i++)
        {
            Elem* elem = fifo->elem+i;
            code(*elem);
        }
    }
    else
    {
        int f = from+fifo->head;
        if (f>=fifo->max_elems)
            f-=fifo->max_elems;
        int to = min(f + count, fifo->max_elems);
        for (int i = f; i<to; i++)
        {
            Elem* elem = fifo->elem+i;
            code(*elem);
        }
        to = count - (to-f);
        for (int i = 0; i<to; i++)
        {
            Elem* elem = fifo->elem+i;
            code(*elem);
        }
    }
}

答案 1 :(得分:2)

另一种方法是完全采用STL样式:创建FIFOIterator类并在FIFO类上提供begin()end()函数。这是一个(不完整的)例子:

template <typename T>
struct FIFO
{
    class FIFOIterator
    {
    public:
        using difference_type = ptrdiff_t;
        using value_type = T;
        using reference = T&;
        using pointer = T*;
        using iterator_category = std::forward_iterator_tag;

        FIFOIterator() :
            fifo{ nullptr },
            index{ 0 }
        {}

        FIFOIterator(FIFO & fifo_in, size_t index_in) :
            fifo{ &fifo_in },
            index{ index_in }
        {
        }

        T & operator*()
        {
            return (*fifo)[index];
        }

        FIFOIterator & operator++()
        {
            ++index;
            return *this;
        }

        bool operator==(const FIFOIterator & rhs)
        {
            return index == rhs.index;
        }

        bool operator!=(const FIFOIterator & rhs)
        {
            return !(operator==(rhs));
        }

    private:
        size_t index;
        FIFO * fifo;
    };

    using iterator = FIFOIterator;

    FIFO(size_t mx) :
        head{ 0 },
        elems{ 0 },
        max_elems{ mx },
        elem{ new T[max_elems] }
    {
    }

    ~FIFO()
    {
        delete[] elem;
    }

    size_t elems;
    size_t max_elems;

    T* elem; // [max_elems]

    size_t head;

    void push(const T & e)
    {
        // int i = (elems+head) % max_elems;

        if (elems < max_elems)
        {
            ++elems;
        }

        elem[head] = e;

        ++head;
        if (head == max_elems)
        {
            head = 0;
        }
    }

    T & operator[](size_t i)
    {
        size_t offset{ head };
        if (elems < max_size)
        {
            offset = 0;
        }
        size_t j = i + offset;
        if (j >= max_elems)
        {
            j -= max_elems;
        }

        return elem[j];
    }

    FIFOIterator begin()
    {
        return FIFOIterator(*this, 0);
    }

    FIFOIterator end()
    {
        return FIFOIterator(*this, elems);
    }
};

使用上述内容,可以将STL算法与FIFO一起使用,例如,

template <typename T>
void printFifo(FIFO<T> & fifo)
{
    std::for_each(fifo.begin(), fifo.end(), [](T & val) { std::cout << val << ", "; });
    std::cout << std::endl;
}

有几点需要注意:

  • 我已将FIFO转换为模板化类 - 您可以在不进行模板化的情况下执行此操作(尽管我会对其进行模板化,以便我可以将其重用于其他元素类型)
  • 我已将int替换为size_t,因为这是规范大小类型
  • 我没有测试过这段代码的性能(虽然我希望它会相当不错)
  • 实际上,您应该创建const访问者const T & FIFO::operator[](size_t) const和关联的const_iterator(因此此示例未完成)
  • 确实 还会实现FIFO的复制构造函数和复制赋值运算符,即使您只是声明它们是私有的,因为该类不安全复制目前的形式(无论是我的例子还是你的例子)
  • 确实 将您的数据成员设为私有并提供访问者功能
  • 即使你没有做任何我推荐的 实现FIFO析构函数来删除构造函数中分配的内存,否则你会泄漏内存