1 // ---------------------------------------------------------------------------- 2 // fqueue.h 3 // 4 // Copyright (C) 2007-2008 5 // Stelios Bounanos, M0GLD 6 // 7 // This file is part of fldigi. 8 // 9 // fldigi is free software; you can redistribute it and/or modify 10 // it under the terms of the GNU General Public License as published by 11 // the Free Software Foundation; either version 3 of the License, or 12 // (at your option) any later version. 13 // 14 // fldigi is distributed in the hope that it will be useful, 15 // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 // GNU General Public License for more details. 18 // 19 // You should have received a copy of the GNU General Public License 20 // along with this program. If not, see <http://www.gnu.org/licenses/>. 21 // ---------------------------------------------------------------------------- 22 23 #ifndef FQUEUE_H_ 24 #define FQUEUE_H_ 25 26 #include <stdexcept> 27 #include <cassert> 28 #include "ringbuffer.h" 29 #include "util.h" 30 // #include <iostream> 31 // #include <cstdio> 32 // #include <stacktrace.h> 33 34 #define FQUEUE_SIZE 2048 35 #define FIFO_SIZE (FQUEUE_SIZE * 4) 36 37 class func_base 38 { 39 public: 40 virtual void destroy(bool run) = 0; ~func_base()41 virtual ~func_base() { } 42 }; 43 44 template <typename F> 45 class func_wrap : public func_base 46 { 47 public: func_wrap(const F & f_)48 explicit func_wrap(const F &f_) : f(f_) { } destroy(bool run)49 virtual void destroy(bool run) 50 { 51 if (run) f(); 52 this->~func_wrap(); 53 } 54 private: 55 F f; 56 }; 57 58 59 class fqueue 60 { 61 typedef ringbuffer<char> fqueue_ringbuffer_t; 62 63 public: 64 fqueue(size_t count = FQUEUE_SIZE, size_t blocksize_ = 128) blocksize(blocksize_)65 : blocksize(blocksize_) 66 { 67 rb = new fqueue_ringbuffer_t(blocksize * count); 68 } ~fqueue()69 ~fqueue() 70 { 71 drop(); 72 delete rb; 73 } 74 empty(void)75 bool empty(void) { return rb->read_space() == 0; } full(void)76 bool full(void) { return rb->write_space() == 0; } size(void)77 size_t size(void) { return rb->read_space() / blocksize; } 78 79 template <class T> push(const T & t)80 bool push(const T& t) 81 { 82 // If we have any space left at all, it will be at least 83 // a blocksize. It will not wrap around the end of the rb. 84 if (unlikely(rb->get_wv(wvec, blocksize) < blocksize)) 85 return false; 86 87 assert(blocksize >= sizeof(func_wrap<T>)); 88 // we assume a no-throw ctor! 89 new (wvec[0].buf) func_wrap<T>(t); 90 rb->write_advance(blocksize); 91 92 return true; 93 } 94 95 bool pop(bool exec = false) 96 { 97 if (rb->get_rv(rvec, blocksize) < blocksize) 98 return false; 99 reinterpret_cast<func_base *>(rvec[0].buf)->destroy(exec); 100 rb->read_advance(blocksize); 101 102 return true; 103 } 104 execute(void)105 bool execute(void) { return pop(true); } 106 drop(void)107 size_t drop(void) 108 { 109 size_t n = 0; 110 while (pop(false)) 111 ++n; 112 return n; 113 } 114 115 protected: 116 fqueue_ringbuffer_t* rb; 117 fqueue_ringbuffer_t::vector_type rvec[2], wvec[2]; 118 size_t blocksize; 119 }; 120 121 #endif // FQUEUE_H_ 122 123 // Local Variables: 124 // mode: c++ 125 // c-file-style: "linux" 126 // End: 127