diff --git a/miosix/kernel/intrusive.h b/miosix/kernel/intrusive.h index 3b4681dbe68134ed31723ae163f7f6846d09e2bc..b15922925bd4fba8a83930648c5b2c059ec8c97a 100644 --- a/miosix/kernel/intrusive.h +++ b/miosix/kernel/intrusive.h @@ -634,188 +634,218 @@ intrusive_ref_ptr<T> atomic_exchange(intrusive_ref_ptr<T> *p, return p->atomic_exchange(r); } -template <typename ItemT> -class IntrusiveList; +template <typename T> +class IntrusiveList; //Forward declaration + /** - * Class: IntrusiveListItem + * Base class from which all items to be put in an IntrusiveList must derive, + * contains the next and prev pointer that create the list */ class IntrusiveListItem { -public: - IntrusiveListItem(){ - next = NULL; - prev = NULL; - } private: - IntrusiveListItem *next; - IntrusiveListItem *prev; + IntrusiveListItem *next=nullptr; + IntrusiveListItem *prev=nullptr; template<typename T> friend class IntrusiveList; - }; /** - * Class: IntrusiveList - * ItemT should be a subclass of IntrusiveListItem + * A doubly linked list that only accepts objects that derive from + * IntrusiveListItem. + * + * Compared to std::list, this class offers the guarantee that no dynamic memory + * allocation is performed. Differently from std::list, objects are not copied + * when put in the list, so this is a non-owning container. The caller is + * responsible for managing the lifetime of objects put in this list. */ -template <typename ItemT> +template <typename T> class IntrusiveList { public: - class iterator{ + class iterator + { private: - ItemT *cur; + T *cur; public: - iterator(ItemT *_cur) : cur(_cur){} - iterator operator++(int) {cur = static_cast<ItemT*>(cur->next);} - iterator operator--(int) {cur = static_cast<ItemT*>(cur->prev);} - ItemT* operator*() {return cur;} - bool operator==(const iterator& rhs) {return cur==rhs.cur;} - bool operator!=(const iterator& rhs) {return cur!=rhs.cur;} + iterator(T *cur) : cur(cur) {} + iterator operator++(int) { cur = static_cast<T*>(cur->next); } + iterator operator--(int) { cur = static_cast<T*>(cur->prev); } + T* operator*() { return cur; } + bool operator==(const iterator& rhs) { return cur==rhs.cur; } + bool operator!=(const iterator& rhs) { return cur!=rhs.cur; } }; - IntrusiveList() + + IntrusiveList() : head(&emptyListItem), tail(&emptyListItem) { emptyListItem.next = &emptyListItem; emptyListItem.prev = &emptyListItem; - head = &emptyListItem; - rear = &emptyListItem; - } - void push_back(ItemT *item){ - item->next = &emptyListItem; - item->prev = rear; - rear = item; - emptyListItem.prev = rear; - if (head==&emptyListItem){ - head = rear; - emptyListItem.next = head; - }else - item->prev->next = item; } + + void push_back(T *item); + /** * Removes the last element in the list. */ - void pop_back() - { - if (rear == &emptyListItem) return; - if (rear == head) - { - head->next = NULL; - head->prev = NULL; - emptyListItem.next = &emptyListItem; - emptyListItem.prev = &emptyListItem; - rear = &emptyListItem; - head = &emptyListItem; - }else{ - rear->prev->next = &emptyListItem; - emptyListItem.prev = rear->prev; - rear->prev = NULL; - rear->next = NULL; - rear = static_cast<ItemT*>(emptyListItem.prev); - } - } - void push_front(ItemT *item) - { - item->prev = &emptyListItem; - if (head != &emptyListItem) - { - item->next = head; - item->next->prev = item; - emptyListItem.next = item; - }else{ - item->next = &emptyListItem; - rear = item; - emptyListItem.prev = item; - emptyListItem.next = item; - } - head = item; - - } + void pop_back(); + + void push_front(T *item); + /** * Removes the first item (head) of the list. */ - void pop_front() - { - if (head==&emptyListItem) return; - if (rear == head) - { - head->next = NULL; - head->prev = NULL; - emptyListItem.next = &emptyListItem; - emptyListItem.prev = &emptyListItem; - rear = &emptyListItem; - head = &emptyListItem; - }else{ - head->next->prev = &emptyListItem; - head->prev = NULL; - emptyListItem.next = head->next; - head->next = NULL; - head = (ItemT*)static_cast<IntrusiveListItem>(emptyListItem).next; - } - } + void pop_front(); + /** * Inserts the given item before the position indicated by the iterator */ - void insert(iterator position, ItemT *item) - { - if (head==&emptyListItem){ - head = item; - rear = item; - item->next = &emptyListItem; - item->prev = &emptyListItem; - emptyListItem.next = item; - emptyListItem.prev = item; - return; - } - item->next = static_cast<IntrusiveListItem *>(*position); - item->prev = static_cast<IntrusiveListItem *>(*position)->prev; - item->prev->next = item; - (*position)->prev = item; - if (item->prev == &emptyListItem) - head = item; - if (item->next == &emptyListItem) - rear = item; - } + void insert(iterator position, T *item); + /** * Removes the specified item from the list. * @param item */ - void erase(iterator it) - { - if ((*it)==&emptyListItem) return; - (*it)->next->prev = (*it)->prev; - (*it)->prev->next = (*it)->next; - (*it)->next = NULL; - (*it)->prev = NULL; - head = (ItemT*)static_cast<IntrusiveListItem>(emptyListItem).next; - rear = (ItemT*)static_cast<IntrusiveListItem>(emptyListItem).prev; - } + void erase(iterator it); + iterator begin() { return iterator(head); } + iterator end() { return iterator(&emptyListItem); } - ItemT* front() + + T* front() { return head; } - ItemT* back() + + T* back() { - return rear; + return tail; } + bool empty() const { - return (head==&emptyListItem); + return head==&emptyListItem; } private: - ItemT *head; - ItemT *rear; - ItemT emptyListItem; + void removeLastItem() + { + head->next = nullptr; + head->prev = nullptr; + emptyListItem.next = &emptyListItem; + emptyListItem.prev = &emptyListItem; + tail = &emptyListItem; + head = &emptyListItem; + } + + T *head; + T *tail; + T emptyListItem; }; +template<typename T> +void IntrusiveList<T>::push_back(T *item) +{ + item->next = &emptyListItem; + item->prev = tail; + tail = item; + emptyListItem.prev = item; + if(head==&emptyListItem) + { + head = tail; + emptyListItem.next = head; + } else item->prev->next = item; +} + +template<typename T> +void IntrusiveList<T>::pop_back() +{ + if(tail == head) + { + //Note: this is safe also in the case of pop_back of an empty list + //by mistake + removeLastItem(); + } else { + tail->prev->next = &emptyListItem; + emptyListItem.prev = tail->prev; + tail->prev = nullptr; + tail->next = nullptr; + tail = static_cast<T*>(emptyListItem.prev); + } +} + +template<typename T> +void IntrusiveList<T>::push_front(T *item) +{ + item->prev = &emptyListItem; + if(head != &emptyListItem) + { + item->next = head; + item->next->prev = item; + emptyListItem.next = item; + } else { + item->next = &emptyListItem; + tail = item; + emptyListItem.prev = item; + emptyListItem.next = item; + } + head = item; +} + +template<typename T> +void IntrusiveList<T>::pop_front() +{ + if(tail == head) + { + //Note: this is safe also in the case of pop_back of an empty list + //by mistake + removeLastItem(); + } else { + head->next->prev = &emptyListItem; + head->prev = nullptr; + emptyListItem.next = head->next; + head->next = nullptr; + head = static_cast<T*>(emptyListItem).next; + } +} + +template<typename T> +void IntrusiveList<T>::insert(iterator position, T *item) +{ + if(head==&emptyListItem) + { + head = item; + tail = item; + item->next = &emptyListItem; + item->prev = &emptyListItem; + emptyListItem.next = item; + emptyListItem.prev = item; + return; + } + item->next = static_cast<IntrusiveListItem *>(*position); //FIXME: do we need this upcast? + item->prev = static_cast<IntrusiveListItem *>(*position)->prev; + item->prev->next = item; + (*position)->prev = item; + if(item->prev == &emptyListItem) head = item; + if(item->next == &emptyListItem) tail = item; +} + +template<typename T> +void IntrusiveList<T>::erase(iterator it) +{ + if((*it)==&emptyListItem) return; + (*it)->next->prev = (*it)->prev; + (*it)->prev->next = (*it)->next; + (*it)->next = nullptr; + (*it)->prev = nullptr; + head = static_cast<T*>(emptyListItem.next); + tail = static_cast<T*>(emptyListItem.prev); +} } //namespace miosix