diff --git a/ChangeLog b/ChangeLog index 74a8ebd..cd043ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-05-19 Richard Frith-Macdonald + + * GNUmakefile: Add FIFO + * Performance.h: Add FIFO + * GSFIFO.h: Add a FIFO class + * GSFIFO.m: Add a FIFO class + 2011-03-08 Richard Frith-Macdonald * GNUmakefile: Bump version number for next release. diff --git a/GSFIFO.h b/GSFIFO.h index 958d2a2..89b812f 100644 --- a/GSFIFO.h +++ b/GSFIFO.h @@ -65,11 +65,11 @@ @public /* While the following instance variables are nominally public, they are in * fact only intended to be used by the provided inline functions ... you - * should not acces them direcdtly in your own code. + * should not access them directly in your own code. */ + volatile uint64_t _head; + volatile uint64_t _tail; id *_items; - uint64_t _head; - uint64_t _tail; uint32_t _capacity; @private uint16_t granularity; @@ -81,6 +81,10 @@ NSString *name; } +/** Returns the approximate number of objects in the FIFO. + */ +- (NSUInteger) count; + /** Gets the next object from the FIFO, blocking if necessary until an * object is available. Raises an exception if the FIFO is configured * with a timeout and it is exceeded. @@ -115,14 +119,25 @@ * with a timeout and it is exceeded. */ - (void) put: (id)item; + +/** Checks the FIFO and returns the first available object or nil if the + * FIFO is empty. + */ +- (id) tryGet; + +/** Attempts to put an item into the FIFO, returning YES on success or NO + * if the FIFO is full. + */ +- (BOOL) tryPut: (id)item; @end /** Function to efficiently get an item from a fast FIFO.
+ * Returns nil if the FIFO is empty.
* Warning ... only for use if the FIFO is NOT configured for multiple * consumers. */ static inline id -GSGetFastFIFO(GSFIFO *receiver) +GSGetFastNonBlockingFIFO(GSFIFO *receiver) { if (receiver->_head > receiver->_tail) { @@ -132,23 +147,56 @@ GSGetFastFIFO(GSFIFO *receiver) receiver->_tail++; return object; } - return [receiver get]; + return nil; +} + +/** Function to efficiently get an item from a fast FIFO, blocking if + * necessary until an object is available or the timeout occurs.
+ * Warning ... only for use if the FIFO is NOT configured for multiple + * consumers. + */ +static inline id +GSGetFastFIFO(GSFIFO *receiver) +{ + id object = GSGetFastNonBlockingFIFO(receiver); + + if (nil == object) + { + object = [receiver get]; + } + return object; } /** Function to efficiently put an item to a fast FIFO.
+ * Returns YES on success, NO on failure (FIFO is full).
+ * Warning ... only for use if the FIFO is NOT configured for multiple + * producers. + */ +static inline BOOL +GSPutFastNonBlockingFIFO(GSFIFO *receiver, id item) +{ + if (receiver->_head - receiver->_tail < receiver->_capacity) + { + receiver->_items[receiver->_head % receiver->_capacity] = item; + receiver->_head++; + return YES; + } + return NO; +} + +/** Function to efficiently put an item to a fast FIFO, blocking if + * necessary untile there is space in the FIFO or until the timeout + * occurs.
* Warning ... only for use if the FIFO is NOT configured for multiple * producers. */ static inline void GSPutFastFIFO(GSFIFO *receiver, id item) { - if (receiver->_head - receiver->_tail < receiver->_capacity) + if (NO == GSPutFastNonBlockingFIFO(receiver, item)) { - receiver->_items[receiver->_head % receiver->_capacity] = item; - receiver->_head++; - return; + [receiver put: item]; } - [receiver put: item]; } #endif diff --git a/GSFIFO.m b/GSFIFO.m index 32a10fb..3f160c0 100644 --- a/GSFIFO.m +++ b/GSFIFO.m @@ -41,6 +41,11 @@ [super dealloc]; } +- (NSUInteger) count +{ + return (NSUInteger)(_head - _tail); +} + - (NSString*) description { return [NSString stringWithFormat: @@ -194,5 +199,63 @@ [putLock unlock]; } +- (id) tryGet +{ + id obj; + + if (nil == getLock) + { + if (_head > _tail) + { + obj = _items[_tail % _capacity]; + _tail++; + return obj; + } + emptyCount++; + } + else + { + [getLock lock]; + if (_head > _tail) + { + obj = _items[_tail % _capacity]; + _tail++; + [getLock unlock]; + return obj; + } + emptyCount++; + [getLock unlock]; + } + return nil; +} + +- (BOOL) tryPut: (id)item +{ + if (nil == putLock) + { + if (_head - _tail < _capacity) + { + _items[_head % _capacity] = item; + _head++; + return YES; + } + fullCount++; + } + else + { + [putLock lock]; + if (_head - _tail < _capacity) + { + _items[_head % _capacity] = item; + _head++; + [putLock unlock]; + return YES; + } + fullCount++; + [putLock unlock]; + } + return NO; +} + @end