#ifndef __FIFO_H__ #define __FIFO_H__ #include #include "util/exception_format.h" #ifndef NULL_CHECK #define NULL_CHECK 1 //0 #endif #ifndef INDEX_CHECK #define INDEX_CHECK 1 //0 #endif #ifndef min_macro #define min_macro(a, b) ((a < b) ? (a) : (b)) #endif #ifndef max_macro #define max_macro(a, b) ((a > b) ? (a) : (b)) #endif #if ENABLE_EXCEPTION_THROW #include #include /** * @brief FIFOに関わる例外 * * */ class FIFOException: public std::exception{ private: std::string what_str; public: /** * コンストラクタ。 * * @param what_arg エラー内容 */ FIFOException(const std::string &what_arg) : what_str(what_arg){} /** * デストラクタ。 * */ ~FIFOException() throw(){} /** * エラー内容を取得します。 * * @return (chsr *) エラー内容 */ const char *what() const throw(){ return what_str.c_str(); } }; #endif struct memcpy_t { template memcpy_t(const StorageT *src, StorageT *dist){ std::memcpy(dist, src, sizeof(StorageT)); } template memcpy_t(const StorageT *src, StorageT *dist, SizeT size){ std::memcpy(dist, src, sizeof(StorageT) * size); } }; struct operator_eq_t { template operator_eq_t(const StorageT *src, StorageT *dist){ *dist = *src; } template operator_eq_t(const StorageT *src, StorageT *dist, SizeT size){ while(size--){ *(dist++) = *(src++); } } }; template < typename StorageT, typename DuplicatorT = memcpy_t > class FIFO { public: typedef StorageT storage_t; static const unsigned storage_bytes; protected: unsigned int capacity; StorageT *storage; StorageT *prius; StorageT *follower; #ifndef BOOL_IS_UCHAR typedef bool bool_t; #else typedef unsigned char bool_t; #endif public: FIFO(const unsigned int &_capacity) #if ENABLE_EXCEPTION_THROW throw(FIFOException) #endif : storage(NULL) { TRY( { storage = new StorageT[_capacity]; capacity = _capacity; prius = follower = storage; } ) CATCH( bad_alloc, { capacity = 0; prius = follower = NULL; throw FIFOException("lack of memory"); } ) } FIFO() : storage(NULL), capacity(0), prius(NULL), follower(NULL){} ~FIFO(){ delete [] storage; } unsigned int size() const{ return capacity; } int stored() const { StorageT *_prius(prius), *_follower(follower); return (_prius >= _follower ? _prius - _follower : _prius + capacity - _follower); } bool_t is_empty() const { return prius == follower; } int margin() const { StorageT *_prius(prius), *_follower(follower); return (_follower <= _prius ? _follower + capacity - _prius : _follower - _prius) - 1; } bool_t has_margin() const { return margin() > 0; } /** * FIFOに書き出します * * @param data * @param size * @return (int) */ unsigned int write(StorageT *values, unsigned int size){ unsigned int _size; StorageT *prius_next; #if NULL_CHECK if(values == NULL){return 0;} #endif size = min_macro(margin(), size); _size = storage + capacity - prius; if(_size <= size){ DuplicatorT(values, prius, _size); prius_next = storage; values += _size; _size = size - _size; }else{ prius_next = prius; _size = size; } if(_size > 0){ DuplicatorT(values, prius_next, _size); prius_next += _size; } prius = prius_next; return size; } /** * FIFOに書き出します * * @param data * @return (int) */ unsigned int push(const StorageT *value){ #if NULL_CHECK if(value == NULL){return 0;} #endif { StorageT *next(prius + 1); if(next == (storage + capacity)) next = storage; if(next != follower){ DuplicatorT(value, prius); prius = next; return 1; }else{ return 0; } } } unsigned int skip(unsigned int size){ unsigned int _size; StorageT *follower_next; size = min_macro(stored(), size); _size = storage + capacity - follower; if(_size <= size){ follower_next = storage; _size = size - _size; }else{ follower_next = follower; _size = size; } if(_size > 0){ follower_next += _size; } follower = follower_next; return size; } /** * FIFOから読み込みます * * @param buffer * @param size * @return (int) */ unsigned int read(StorageT *buffer, unsigned int size){ unsigned int _size; StorageT *follower_next; #if NULL_CHECK if(buffer == NULL){return 0;} #endif size = min_macro(stored(), size); _size = storage + capacity - follower; if(_size <= size){ DuplicatorT(follower, buffer, _size); follower_next = storage; buffer += _size; _size = size - _size; }else{ follower_next = follower; _size = size; } if(_size > 0){ DuplicatorT(follower_next, buffer, _size); follower_next += _size; } follower = follower_next; return size; } /** * FIFOから読み込みます * * @param buffer * @return (int) */ unsigned int pop(StorageT *buffer){ #if NULL_CHECK if(buffer == NULL){return 0;} #endif if(follower != prius){ DuplicatorT(follower, buffer); follower++; if(follower == storage + capacity){ follower = storage; } return 1; }else{ return 0; } } //protected: StorageT &operator[] (const int &index) const #if INDEX_CHECK #if ENABLE_EXCEPTION_THROW throw(FIFOException) #endif #endif { StorageT *result; if(index >= 0){ #if INDEX_CHECK #if ENABLE_EXCEPTION_THROW if(index >= stored()){ throw FIFOException("out of bounds"); } #endif #endif result = follower + index; if(result >= (storage + capacity)){ result -= capacity; } }else{ #if INDEX_CHECK #if ENABLE_EXCEPTION_THROW if(index < -stored()){ throw FIFOException("out of bounds"); } #endif #endif result = prius + index; if(result < storage){ result += capacity; } } return *result; } StorageT &head() const #if INDEX_CHECK #if ENABLE_EXCEPTION_THROW throw(FIFOException) #endif #endif { return operator[](0); } /** * FIFOの中身を調査します * * @param buffer * @param size * @param offset * @return (int) */ unsigned int inspect( StorageT *buffer, unsigned int size, unsigned int offset) const { unsigned int _size; StorageT *follower2; #if NULL_CHECK if(buffer == NULL){return 0;} #endif if(stored() <= offset){return 0;} size = min_macro(stored() - offset, size); if((follower2 = follower + offset) >= (storage + capacity)){ follower2 -= capacity; } _size = storage + capacity - follower2; if(_size <= size){ DuplicatorT(follower2, buffer, _size); follower2 = storage; buffer += _size; _size = size - _size; }else{_size = size;} if(_size > 0){ DuplicatorT(follower2, buffer, _size); } return size; } /** * FIFOの中身を調査します * * @param buffer * @param size * @param offset * @return (int) */ unsigned int inspect(StorageT *buffer, unsigned int size) const { return inspect(buffer, size, 0); } /** * リサイズします。 * * @param _capacity 新しいサイズ */ void resize(const unsigned int &_capacity) #if ENABLE_EXCEPTION_THROW throw(FIFOException) #endif { TRY( { StorageT *new_storage = new StorageT[_capacity]; prius = new_storage + inspect(new_storage, _capacity); follower = new_storage; if(storage){delete [] storage;} storage = new_storage; capacity = _capacity; } ) CATCH( bad_alloc, { throw FIFOException("lack of memory"); } ) } }; template < typename StorageT, typename DuplicatorT > const unsigned FIFO::storage_bytes = sizeof(StorageT); #endif /* __FIFO_H__ */