我有以下方式实现的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;但不是宏观?
答案 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 T & FIFO::operator[](size_t) const
和关联的const_iterator
(因此此示例未完成)FIFO
析构函数来删除构造函数中分配的内存,否则你会泄漏内存