| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #ifndef _DECAF_UTIL_QUEUE_H_ |
| #define _DECAF_UTIL_QUEUE_H_ |
| |
| #include <list> |
| #include <vector> |
| #include <decaf/util/concurrent/Mutex.h> |
| #include <decaf/lang/Exception.h> |
| |
| namespace decaf{ |
| namespace util{ |
| |
| /** |
| * The Queue class accepts messages with an psuh(m) command |
| * where m is the message to be queued. It destructively |
| * returns the message with pop(). pop() returns messages in |
| * the order they were enqueued. |
| * |
| * Queue is implemented with an instance of the STL queue object. |
| * The interface is essentially the same as that of the STL queue |
| * except that the pop method actually reaturns a reference to the |
| * element popped. This frees the app from having to call the |
| * <code>front</code> method before calling pop. |
| * |
| * Queue<string> sq; // make a queue to hold string messages |
| * sq.push(s); // enqueues a message m |
| * string s = sq.pop(); // dequeues a message |
| * |
| * = DESIGN CONSIDERATIONS |
| * |
| * The Queue class inherits from the Synchronizable interface and |
| * provides methods for locking and unlocking this queue as well as |
| * waiting on this queue. In a multi-threaded app this can allow |
| * for multiple threads to be reading from and writing to the same |
| * Queue. |
| * |
| * Clients should consider that in a multiple threaded app it is |
| * possible that items could be placed on the queue faster than |
| * you are taking them off, so protection should be placed in your |
| * polling loop to ensure that you don't get stuck there. |
| */ |
| |
| template <typename T> class DECAF_API Queue : public concurrent::Synchronizable { |
| public: |
| |
| Queue() {} |
| virtual ~Queue() {} |
| |
| /** |
| * Empties this queue. |
| */ |
| void clear() { |
| queue.clear(); |
| } |
| |
| /** |
| * Returns a Reference to the element at the head of the queue |
| * @return reference to a queue type object or (safe) |
| */ |
| T& front() { |
| if( queue.empty() ) { |
| return safe; |
| } |
| |
| return queue.front(); |
| } |
| |
| /** |
| * Returns a Reference to the element at the head of the queue |
| * @return reference to a queue type object or (safe) |
| */ |
| const T& front() const { |
| if( queue.empty() ) { |
| return safe; |
| } |
| |
| return queue.front(); |
| } |
| |
| /** |
| * Returns a Reference to the element at the tail of the queue |
| * @return reference to a queue type object or (safe) |
| */ |
| T& back() { |
| if( queue.empty() ) { |
| return safe; |
| } |
| |
| return queue.back(); |
| } |
| |
| /** |
| * Returns a Reference to the element at the tail of the queue |
| * @return reference to a queue type object or (safe) |
| */ |
| const T& back() const { |
| if( queue.empty() ) { |
| return safe; |
| } |
| |
| return queue.back(); |
| } |
| |
| /** |
| * Places a new Object at the Tail of the queue |
| * @param t - Queue Object Type reference. |
| */ |
| void push( const T &t ) { |
| queue.push_back( t ); |
| } |
| |
| /** |
| * Places a new Object at the front of the queue |
| * @param t - Queue Object Type reference. |
| */ |
| void enqueueFront( const T &t ) { |
| queue.push_front( t ); |
| } |
| |
| /** |
| * Removes and returns the element that is at the Head of the queue |
| * @return reference to a queue type object or (safe) |
| */ |
| T pop() { |
| if( queue.empty() ) { |
| return safe; |
| } |
| |
| // Pop the element into a temp, since we need to remain locked. |
| // this means getting front and then popping. |
| T temp = queue.front(); |
| queue.pop_front(); |
| |
| return temp; |
| } |
| |
| /** |
| * Gets the Number of elements currently in the Queue |
| * @return Queue Size |
| */ |
| size_t size() const{ |
| return queue.size(); |
| } |
| |
| /** |
| * Checks if this Queue is currently empty |
| * @return boolean indicating queue emptiness |
| */ |
| bool empty() const { |
| return queue.empty(); |
| } |
| |
| /** |
| * @return the all values in this queue as a std::vector. |
| */ |
| virtual std::vector<T> toArray() const { |
| std::vector<T> valueArray( queue.begin(), queue.end() ); |
| return valueArray; |
| } |
| |
| /** |
| * Reverses the order of the contents of this queue and stores them |
| * in the target queue. |
| * @param target - The target queue that will receive the contents of |
| * this queue in reverse order. |
| */ |
| void reverse( Queue<T>& target ) const { |
| target.queue.insert( target.queue.end(), queue.rbegin(), queue.rend() ); |
| } |
| |
| /** |
| * Locks the object. |
| */ |
| virtual void lock() throw( lang::Exception ){ |
| mutex.lock(); |
| } |
| |
| /** |
| * Unlocks the object. |
| */ |
| virtual void unlock() throw( lang::Exception ){ |
| mutex.unlock(); |
| } |
| |
| /** |
| * Waits on a signal from this object, which is generated |
| * by a call to Notify. Must have this object locked before |
| * calling. |
| */ |
| virtual void wait() throw( lang::Exception ){ |
| mutex.wait(); |
| } |
| |
| /** |
| * Waits on a signal from this object, which is generated |
| * by a call to Notify. Must have this object locked before |
| * calling. This wait will timeout after the specified time |
| * interval. |
| * @param millisecs time to wait, or WAIT_INIFINITE |
| * @throws ActiveMQException |
| */ |
| virtual void wait( unsigned long millisecs ) |
| throw( lang::Exception ) { |
| |
| mutex.wait(millisecs); |
| } |
| |
| /** |
| * Signals a waiter on this object that it can now wake |
| * up and continue. Must have this object locked before |
| * calling. |
| */ |
| virtual void notify() throw( lang::Exception ){ |
| mutex.notify(); |
| } |
| |
| /** |
| * Signals the waiters on this object that it can now wake |
| * up and continue. Must have this object locked before |
| * calling. |
| */ |
| virtual void notifyAll() throw( lang::Exception ){ |
| mutex.notifyAll(); |
| } |
| |
| public: // Statics |
| |
| /** |
| * Fetch a reference to the safe value this object will return |
| * when there is nothing to fetch from the queue. |
| * @return Reference to this Queues safe object |
| */ |
| static const T& getSafeValue() { return safe; } |
| |
| private: |
| |
| // The real queue |
| std::list<T> queue; |
| |
| // Object used for sync |
| util::concurrent::Mutex mutex; |
| |
| // Safe value used when pop, front or back are |
| // called and the queue is empty. |
| static T safe; |
| |
| }; |
| |
| //-----{ Static Init }----------------------------------------------------// |
| template <typename T> T Queue<T>::safe; |
| |
| }} |
| |
| #endif /*_DECAF_UTIL_QUEUE_H_*/ |