// Copyright (C) 2004 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_QUEUE_KERNEl_2_ #define DLIB_QUEUE_KERNEl_2_ #include "queue_kernel_abstract.h" #include "../algs.h" #include "../assert.h" #include "../interfaces/enumerable.h" #include "../interfaces/remover.h" #include "../serialize.h" namespace dlib { template < typename T, unsigned long block_size, typename mem_manager = default_memory_manager > class queue_kernel_2 : public enumerable, public remover { /*! REQUIREMENTS ON block_size 0 < block_size < 2000000000 INITIAL VALUE queue_size == 0 current_element == 0 at_start_ == true CONVENTION queue_size == the number of elements in the queue at_start() == at_start_ current_element_valid() == (current_element != 0) if (current_element_valid()) then element() == current_element->item[current_element_pos] if (queue_size > 0) { in->item[in_pos] == the spot where we will put the next item added into the queue out->item[out_pos] == current() when enqueuing elements inside each node item[0] is filled first, then item[1], then item[2], etc. each node points to the node inserted after it except for the most recently inserted node. } !*/ struct node { node* next; T item[block_size]; }; public: typedef T type; typedef mem_manager mem_manager_type; queue_kernel_2 ( ) : in(0), out(0), queue_size(0), current_element(0), at_start_(true) { } virtual ~queue_kernel_2 ( ); inline void clear( ); void enqueue ( T& item ); void dequeue ( T& item ); void cat ( queue_kernel_2& item ); T& current ( ); const T& current ( ) const; void swap ( queue_kernel_2& item ); // functions from the remover interface inline void remove_any ( T& item ); // functions from the enumerable interface inline size_t size ( ) const; inline bool at_start ( ) const; inline void reset ( ) const; bool current_element_valid ( ) const; inline const T& element ( ) const; inline T& element ( ); bool move_next ( ) const; private: void delete_nodes ( node* start, node* end ); /*! requires - start points to a node in a singly linked list - start->next points to the next node in the list - by following the next pointers you eventually hit the node pointed to by end ensures - calls delete on the start node, the end node, and all nodes in between !*/ // data members typename mem_manager::template rebind::other pool; node* in; node* out; size_t queue_size; size_t in_pos; size_t out_pos; mutable node* current_element; mutable size_t current_element_pos; mutable bool at_start_; // restricted functions queue_kernel_2(queue_kernel_2&); // copy constructor queue_kernel_2& operator=(queue_kernel_2&); // assignment operator }; template < typename T, unsigned long block_size, typename mem_manager > inline void swap ( queue_kernel_2& a, queue_kernel_2& b ) { a.swap(b); } template < typename T, unsigned long block_size, typename mem_manager > void deserialize ( queue_kernel_2& item, std::istream& in ) { try { item.clear(); unsigned long size; deserialize(size,in); T temp; for (unsigned long i = 0; i < size; ++i) { deserialize(temp,in); item.enqueue(temp); } } catch (serialization_error e) { item.clear(); throw serialization_error(e.info + "\n while deserializing object of type queue_kernel_2"); } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > queue_kernel_2:: ~queue_kernel_2 ( ) { COMPILE_TIME_ASSERT(0 < block_size && block_size < (unsigned long)(2000000000)); if (queue_size > 0) delete_nodes(out,in); } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: clear ( ) { if (queue_size > 0) { delete_nodes(out,in); queue_size = 0; } // put the enumerator at the start reset(); } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: enqueue ( T& item ) { if (queue_size == 0) { out = in = pool.allocate(); in_pos = 0; out_pos = 0; } else if (in_pos >= block_size) { in->next = pool.allocate(); in_pos = 0; in = in->next; } exchange(item,in->item[in_pos]); ++in_pos; ++queue_size; // put the enumerator at the start reset(); } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: dequeue ( T& item ) { // swap out into item exchange(item,out->item[out_pos]); ++out_pos; --queue_size; // if this was the last element in this node then remove this node if (out_pos == block_size) { out_pos = 0; node* temp = out; out = out->next; pool.deallocate(temp); } else if (queue_size == 0) { pool.deallocate(out); } // put the enumerator at the start reset(); } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: cat ( queue_kernel_2& item ) { if (queue_size > 0) { T temp; assign_zero_if_built_in_scalar_type(temp); while (item.size() > 0) { item.dequeue(temp); enqueue(temp); } } else { in = item.in; out = item.out; out_pos = item.out_pos; in_pos = item.in_pos; queue_size = item.queue_size; item.queue_size = 0; // put the enumerator at the start reset(); } } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > T& queue_kernel_2:: current ( ) { return out->item[out_pos]; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > const T& queue_kernel_2:: current ( ) const { return out->item[out_pos]; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: swap ( queue_kernel_2& item ) { exchange(in,item.in); exchange(out,item.out); exchange(queue_size,item.queue_size); exchange(in_pos,item.in_pos); exchange(out_pos,item.out_pos); exchange(current_element,item.current_element); exchange(current_element_pos,item.current_element_pos); exchange(at_start_,item.at_start_); pool.swap(item.pool); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // enumerable function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > size_t queue_kernel_2:: size ( ) const { return queue_size; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > bool queue_kernel_2:: at_start ( ) const { return at_start_; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: reset ( ) const { at_start_ = true; current_element = 0; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > bool queue_kernel_2:: current_element_valid ( ) const { return (current_element != 0); } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > const T& queue_kernel_2:: element ( ) const { return current_element->item[current_element_pos]; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > T& queue_kernel_2:: element ( ) { return current_element->item[current_element_pos]; } // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > bool queue_kernel_2:: move_next ( ) const { if (at_start_) { at_start_ = false; // if the queue is empty then there is nothing to do if (queue_size == 0) { return false; } else { current_element = out; current_element_pos = out_pos; return true; } } else if (current_element == 0) { return false; } else { ++current_element_pos; // if we are at the last element then the enumeration has finished if (current_element == in && current_element_pos == in_pos ) { current_element = 0; return false; } else if (current_element_pos == block_size) { current_element_pos = 0; current_element = current_element->next; } return true; } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // remover function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: remove_any ( T& item ) { dequeue(item); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // private member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- template < typename T, unsigned long block_size, typename mem_manager > void queue_kernel_2:: delete_nodes ( node* start, node* end ) { node* temp; while (start != end) { temp = start; start = start->next; pool.deallocate(temp); } pool.deallocate(start); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_QUEUE_KERNEl_2_