source: trunk/packages/vizservers/nanovis/CircularQueue.h @ 2800

Last change on this file since 2800 was 2798, checked in by ldelgass, 12 years ago

Add emacs mode magic line in preparation for indentation cleanup

  • Property svn:eol-style set to native
File size: 4.7 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/* CircularFifo.h
3* Not any company's property but Public-Domain
4* Do with source-code as you will. No requirement to keep this
5* header if need to use it/change it/ or do whatever with it
6*
7* Note that there is No guarantee that this code will work
8* and I take no responsibility for this code and any problems you
9* might get if using it. The code is highly platform dependent!
10*
11* Code & platform dependent issues with it was originally
12* published at http://www.kjellkod.cc/threadsafecircularqueue
13* 2009-11-02
14* @author Kjell Hedström, hedstrom@kjellkod.cc */
15
16#ifndef CIRCULARFIFO_H_
17#define CIRCULARFIFO_H_
18
19/** Circular Fifo (a.k.a. Circular Buffer)
20* Thread safe for one reader, and one writer */
21template<typename Element, unsigned int Size>
22class CircularFifo {
23public:
24   enum {Capacity = Size+1};
25
26   CircularFifo() : tail(0), head(0){}
27   virtual ~CircularFifo() {}
28
29   bool push(Element& item_);
30   bool pop(Element& item_);
31   bool isEmpty() const;
32   bool isFull() const;
33   
34   // INSOO
35   bool push();
36   int tailIndex();
37   bool pop();
38   bool top(Element&);
39   
40public:
41   volatile unsigned int tail; // input index
42   Element array[Capacity];
43   volatile unsigned int head; // output index
44
45   unsigned int increment(unsigned int idx_) const;
46};
47
48
49
50
51/** Producer only: Adds item to the circular queue.
52* If queue is full at 'push' operation no update/overwrite
53* will happen, it is up to the caller to handle this case
54*
55* \param item_ copy by reference the input item
56* \return whether operation was successful or not */
57template<typename Element, unsigned int Size>
58bool CircularFifo<Element, Size>::push(Element& item_)
59{
60   int nextTail = increment(tail);
61   if(((unsigned int) nextTail) != head)
62   {
63      array[tail] = item_;
64      tail = nextTail;
65      return true;
66   }
67
68   // queue was full
69   return false;
70}
71
72template<typename Element, unsigned int Size>
73bool CircularFifo<Element, Size>::top(Element& data)
74{
75   if(head == tail)
76      return false;  // empty queue
77
78   data = array[head];
79   head = increment(head);
80   return true;
81}
82
83
84/** Consumer only: Removes and returns item from the queue
85* If queue is empty at 'pop' operation no retrieve will happen
86* It is up to the caller to handle this case
87*
88* \param item_ return by reference the wanted item
89* \return whether operation was successful or not */
90template<typename Element, unsigned int Size>
91bool CircularFifo<Element, Size>::pop(Element& item_)
92{
93   if(head == tail)
94      return false;  // empty queue
95
96   item_ = array[head];
97   head = increment(head);
98   return true;
99}
100
101/** Consumer only: Removes and returns item from the queue
102* If queue is empty at 'pop' operation no retrieve will happen
103* It is up to the caller to handle this case
104*
105* \param item_ return by reference the wanted item
106* \return whether operation was successful or not */
107template<typename Element, unsigned int Size>
108bool CircularFifo<Element, Size>::pop()
109{
110   if(head == tail)
111      return false;  // empty queue
112   head = increment(head);
113   return true;
114}
115
116/** Useful for testinng and Consumer check of status
117  * Remember that the 'empty' status can change quickly
118  * as the Procuder adds more items.
119  *
120  * \return true if circular buffer is empty */
121template<typename Element, unsigned int Size>
122bool CircularFifo<Element, Size>::isEmpty() const
123{
124   return (head == tail);
125}
126
127/** Useful for testing and Producer check of status
128  * Remember that the 'full' status can change quickly
129  * as the Consumer catches up.
130  *
131  * \return true if circular buffer is full.  */
132template<typename Element, unsigned int Size>
133bool CircularFifo<Element, Size>::isFull() const
134{
135   int tailCheck = (tail+1) % Capacity;
136   return (((unsigned int) tailCheck) == head);
137}
138
139/** Increment helper function for index of the circular queue
140* index is inremented or wrapped
141*
142*  \param idx_ the index to the incremented/wrapped
143*  \return new value for the index */
144template<typename Element, unsigned int Size>
145unsigned int CircularFifo<Element, Size>::increment(unsigned int idx_) const
146{
147   // increment or wrap
148   // =================
149   //    index++;
150   //    if(index == array.lenght) -> index = 0;
151   //
152   //or as written below:   
153   //    index = (index+1) % array.length
154   idx_ = (idx_+1) % Capacity;
155   return idx_;
156}
157
158template<typename Element, unsigned int Size>
159int CircularFifo<Element, Size>::tailIndex()
160{
161   int nextTail = increment(tail);
162   if(((unsigned int)nextTail) != head)
163   {
164      return tail;
165   }
166
167   return -1;
168}
169
170
171template<typename Element, unsigned int Size>
172bool CircularFifo<Element, Size>::push()
173{
174   int nextTail = increment(tail);
175   if(((unsigned int)nextTail) != head)
176   {
177      tail = nextTail;
178      return true;
179   }
180
181   return false;
182}
183
184#endif /* CIRCULARFIFO_H_ */
Note: See TracBrowser for help on using the repository browser.