From 22651db023207d4aa27477b765df8d17a35d7797 Mon Sep 17 00:00:00 2001 From: Simon Rozman Date: Fri, 26 Aug 2016 15:50:24 +0200 Subject: [PATCH] vector_queue template introduced --- README.md | 25 +++ include/WinStd/Common.h | 396 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 421 insertions(+) diff --git a/README.md b/README.md index 88a42e70..a767200f 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,31 @@ winstd::bstr{ preview ([$e.m_h,su]) stringview ([$e.m_h,sub]) } +winstd::vector_queue<*>{ + preview ( + #( + "[", + $e.m_count, + "](", + #array( + expr: $e.m_data._Myptr[($e.m_head + $i)%$e.m_size_max], + size: $e.m_count + ), + ")" + ) + ) + + children ( + #( + #([size] : $e.m_count), + #([capacity] : $e.m_size_max), + #array( + expr: $e.m_data._Myptr[($e.m_head + $i)%$e.m_size_max], + size: $e.m_count + ) + ) + ) +} winstd::sanitizing_vector<*>{ preview ( #( diff --git a/include/WinStd/Common.h b/include/WinStd/Common.h index 7625b51a..9c2da055 100644 --- a/include/WinStd/Common.h +++ b/include/WinStd/Common.h @@ -69,6 +69,7 @@ namespace winstd template struct LocalFree_delete<_Ty[]>; template class handle; template class dplhandle; + template class vector_queue; /// /// \defgroup WinStdExceptions Exceptions @@ -708,6 +709,401 @@ namespace winstd /// @} + + /// + /// Helper class to allow limited size FIFO queues implemented as vector of elements + /// + template + class vector_queue + { + public: + /// + /// Type to measure element count and indices in + /// + typedef size_t size_type; + + /// + /// Element type + /// + typedef T value_type; + + /// + /// Reference to element type + /// + typedef T& reference; + + /// + /// Constant reference to element type + /// + typedef const T& const_reference; + + /// + /// Pointer to element + /// + typedef T* pointer; + + /// + /// Constant pointer to element + /// + typedef const T* const_pointer; + + public: + /// + /// Construct queue of fixed size. + /// + /// \param[in] size_max Maximum number of elements. Please note this cannot be changed later. + /// + inline vector_queue(_In_ size_type size_max) : + m_data(new value_type[size_max]), + m_head(0), + m_count(0), + m_size_max(size_max) + { + } + + /// + /// Copies existing queue. + /// + /// \param[in] other Queue to copy from + /// + inline vector_queue(_In_ const vector_queue &other) : + m_data(new value_type[other.m_size_max]), + m_head(other.m_head), + m_count(other.m_count), + m_size_max(other.m_size_max) + { + // Copy elements. + for (size_type i = 0; i < m_count; i++) { + size_type i_l = abs(i); + m_data[i_l] = other.m_data[i_l]; + } + } + + /// + /// Moves existing queue. + /// + /// \param[inout] other Queue to move + /// + inline vector_queue(_Inout_ vector_queue &&other) : + m_data(std::move(other.m_data)), + m_head(std::move(other.m_head)), + m_count(std::move(other.m_count)), + m_size_max(std::move(other.m_size_max)) + { + // Reset other to consistent state. + other.m_head = 0; + other.m_count = 0; + other.m_size_max = 0; + } + + /// + /// Copies existing queue. + /// + /// \param[in] other Queue to copy from + /// + inline vector_queue& operator=(_In_ const vector_queue &other) + { + if (this != std::addressof(other)) { + m_head = other.m_head; + m_count = other.m_count; + m_size_max = other.m_size_max; + + // Copy elements. + m_data.reset(new value_type[other.m_size_max]); + for (size_type i = 0; i < m_count; i++) { + size_type i_l = abs(i); + m_data[i_l] = other.m_data[i_l]; + } + } + + return *this; + } + + /// + /// Moves existing queue. + /// + /// \param[inout] other Queue to move + /// + inline vector_queue& operator=(_Inout_ vector_queue &&other) + { + if (this != std::addressof(other)) { + m_data = std::move(other.m_data ); + m_head = std::move(other.m_head ); + m_count = std::move(other.m_count ); + m_size_max = std::move(other.m_size_max); + + // Reset other to consistent state. + other.m_head = 0; + other.m_count = 0; + other.m_size_max = 0; + } + + return *this; + } + + /// + /// Returns the number of elements in the vector. + /// + inline size_type size() const + { + return m_count; + } + + /// + /// Returns the number of elements that the queue can contain before overwriting head ones. + /// + inline size_type capacity() const + { + return m_size_max; + } + + /// + /// Erases the elements of the queue. + /// + inline void clear() + { + m_count = 0; + } + + /// + /// Tests if the queue is empty. + /// + inline bool empty() const + { + return m_count == 0; + } + + /// + /// Returns a reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline reference at(_In_ size_type pos) + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline reference operator[](_In_ size_type pos) + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a constant reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline const_reference at(_In_ size_type pos) const + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a constant reference to the element at a specified location in the queue. + /// + /// \param[in] pos The subscript or position number of the element to reference in the queue. + /// + inline const_reference operator[](_In_ size_type pos) const + { + if (pos >= m_count) throw std::invalid_argument("Invalid subscript"); + return m_data[abs(pos)]; + } + + /// + /// Returns a reference to the element at the absolute location in the queue. + /// + /// \note Absolute means "measured from the beginning of the storage". + /// + /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. + /// + inline reference at_abs(_In_ size_type pos) + { + if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); + return m_data[pos]; + } + + /// + /// Returns a constant reference to the element at the absolute location in the queue: measured from the beginning of the storage. + /// + /// \note Absolute means "measured from the beginning of the storage". + /// + /// \param[in] pos The absolute subscript or position number of the element to reference in the queue. + /// + inline const_reference at_abs(_In_ size_type pos) const + { + if (pos >= m_size_max) throw std::invalid_argument("Invalid subscript"); + return m_data[pos]; + } + + /// + /// Copies an existing element to the end of the queue, overriding the first one when queue is out of space. + /// + /// \param[in] v Element to copy to the end of the queue. + /// + /// \returns The absolute subscript or position number the element was copied to. + /// + inline size_type push_back(_In_ const value_type &v) + { + if (m_count < m_size_max) { + size_type pos = abs(m_count); + m_data[pos] = v; + m_count++; + return pos; + } else { + size_type pos = m_head; + m_data[pos] = v; + m_head = abs(1); + return pos; + } + } + + /// + /// Moves the element to the end of the queue, overriding the first one when queue is out of space. + /// + /// \param[in] v Element to move to the end of the queue. + /// + /// \returns The absolute subscript or position number the element was moved to. + /// + inline size_type push_back(_Inout_ value_type&&v) + { + if (m_count < m_size_max) { + size_type pos = abs(m_count); + m_data[pos] = std::move(v); + m_count++; + return pos; + } else { + size_type pos = m_head; + m_data[pos] = std::move(v); + m_head = abs(1); + return pos; + } + } + + /// + /// Removes (dequeues) the last element of the queue. + /// + inline void pop_back() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + m_count--; + } + + /// + /// Copies an existing element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. + /// + /// \param[in] v Element to copy to the head of the queue. + /// + /// \returns The absolute subscript or position number the element was copied to. + /// + inline size_type push_front(_In_ const value_type &v) + { + m_head = abs(-1); + if (m_count < m_size_max) + m_count++; + m_data[m_head] = v; + return m_head; + } + + /// + /// Moves the element to the head of the queue, overriding the last one when queue is out of space and moving all others one place right. + /// + /// \param[in] v Element to move to the head of the queue. + /// + /// \returns The absolute subscript or position number the element was moved to. + /// + inline size_type push_front(_Inout_ value_type&&v) + { + m_head = abs(-1); + if (m_count < m_size_max) + m_count++; + m_data[m_head] = std::move(v); + return m_head; + } + + /// + /// Removes (dequeues) the head element of the queue. + /// + inline void pop_front() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + m_head = abs(1); + m_count--; + } + + /// + /// Returns a reference to the head element in the queue. + /// + inline reference front() + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return m_data[m_head]; + } + + /// + /// Returns a constant reference to the head element in the queue. + /// + inline const_reference front() const + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return m_data[m_head]; + } + + /// + /// Returns a reference to the last element in the queue. + /// + inline reference back() + { + return m_data[tail()]; + } + + /// + /// Returns a constant reference to the last element in the queue. + /// + inline const_reference back() const + { + return m_data[tail()]; + } + + /// + /// Returns absolute subscript or position number of the head element in the queue. The element does not need to exist. + /// + inline size_type head() const + { + return m_head; + } + + /// + /// Returns absolute subscript or position number of the last element in the queue. The element must exist. + /// + inline size_type tail() const + { + if (!m_count) throw std::invalid_argument("Empty storage"); + return abs(m_count - 1); + } + + /// + /// Returns absolute subscript or position number of the given element in the queue. + inline size_type abs(_In_ size_type pos) const + { + return (m_head + pos) % m_size_max; + } + + protected: + std::unique_ptr m_data; ///< Underlying data container + size_type m_head; ///< Index of the first element + size_type m_count; ///< Number of elements + size_type m_size_max; ///< Maximum size + }; + + /// /// \defgroup WinStdExceptions Exceptions /// Additional exceptions