/* * High-level, real-time safe, templated C++ doubly linked list * Copyright (C) 2013 Filipe Coelho * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For a full copy of the GNU General Public License see the COPYING file */ #ifndef __RT_LIST_HPP__ #define __RT_LIST_HPP__ extern "C" { #include "rtmempool/list.h" #include "rtmempool/rtmempool.h" } #include #include typedef struct list_head k_list_head; template class RtList { public: RtList(const size_t minPreallocated, const size_t maxPreallocated) { qcount = 0; ::INIT_LIST_HEAD(&queue); ::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); assert(mempool); } ~RtList() { clear(); ::rtsafe_memory_pool_destroy(mempool); } void resize(const size_t minPreallocated, const size_t maxPreallocated) { clear(); ::rtsafe_memory_pool_destroy(mempool); ::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); assert(mempool); } void clear() { if (! isEmpty()) { RtListData* data; k_list_head* entry; list_for_each(entry, &queue) { data = list_entry(entry, RtListData, siblings); ::rtsafe_memory_pool_deallocate(mempool, data); } } qcount = 0; ::INIT_LIST_HEAD(&queue); } size_t count() const { return qcount; } bool isEmpty() const { return (qcount == 0); //return (list_empty(&queue) != 0); } void append(const T& value, const bool sleepy = false) { RtListData* data; if (sleepy) data = (RtListData*)::rtsafe_memory_pool_allocate_sleepy(mempool); else data = (RtListData*)::rtsafe_memory_pool_allocate_atomic(mempool); if (data) { ::memcpy(&data->value, &value, sizeof(T)); ::list_add_tail(&data->siblings, &queue); qcount++; } } T& getFirst() { return __get(true, false); } T& getFirstAndRemove() { return __get(true, true); } T& getLast() { return __get(false, false); } T& getLastAndRemove() { return __get(false, true); } bool removeOne(const T& value) { RtListData* data; k_list_head* entry; list_for_each(entry, &queue) { data = list_entry(entry, RtListData, siblings); if (data->value == value) { qcount--; ::list_del(entry); ::rtsafe_memory_pool_deallocate(mempool, data); return true; } } return false; } void removeAll(const T& value) { RtListData* data; k_list_head* entry; k_list_head* tmp; list_for_each_safe(entry, tmp, &queue) { data = list_entry(entry, RtListData, siblings); if (data->value == value) { qcount--; ::list_del(entry); ::rtsafe_memory_pool_deallocate(mempool, data); } } } private: size_t qcount; k_list_head queue; RtMemPool_Handle mempool; struct RtListData { T value; k_list_head siblings; }; T& __get(const bool first, const bool doDelete) { if (isEmpty()) { // FIXME ? static T value; static bool reset = true; if (reset) { reset = false; ::memset(&value, 0, sizeof(T)); } return value; } k_list_head* entry = first ? queue.next : queue.prev; RtListData* data = list_entry(entry, RtListData, siblings); T& ret = data->value; if (data && doDelete) { qcount--; ::list_del(entry); ::rtsafe_memory_pool_deallocate(mempool, data); } return ret; } // Non-copyable RtList(const RtList&); RtList& operator= (const RtList&); // Prevent heap allocation static void* operator new (size_t); static void operator delete (void*); }; #endif // __RT_LIST_HPP__