/* * Copyright 2011, 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; * see the COPYING file in the main directory for licensing * information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. 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. */ #ifndef RLIST_H #define RLIST_H #include #include "GPRSInternal.h" // For devassert // A list with random access too. template class RList : public std::list { typedef typename std::list::iterator itr_t; typedef typename std::list type_t; public: T operator[](unsigned ind) { unsigned i = 0; for (itr_t itr = type_t::begin(); itr != type_t::end(); itr++) { if (i++ == ind) return *itr; } return 0; // Since we use 0 to mean unknown, this class can not be used // if this is a valid value of T. Could throw an error instead, // and complicate things for the caller. } bool find(T element) { for (itr_t itr = type_t::begin(); itr != type_t::end(); itr++) { if (*itr == element) { return true; } } return false; } //bool find_safely(T element) { return find(element); } //void push_back_safely(T&val) { assert(! find(val)); std::list::push_back(val); } //void remove_safely(T&val) { std::list::remove(val); } }; // Like RList but add an internal Mutex so it can auto-lock for multi-threads using RlistIteratorThreadSafe. template class RListThreadSafe : RList { Mutex mListLock; bool find_safely(T element) { ScopedLock lock(mListLock); return find(element); } void push_back_safely(T&val) { ScopedLock lock(mListLock); assert(! find(val)); std::list::push_back(val); } void remove_safely(T&val) { ScopedLock lock(mListLock); std::list::remove(val); } }; // Like ScopedLock but creates a scoped iterator especially useful in a for statement. // Use like this: given a list and a mutex to protect access to the list: // class T; list mylist; Mutex mymutex; for (ScopedIterator >(mylist,mymutex); next(var);) template > class ScopedIterator { ListType &mPList; Mutex& mPMutex; public: typename ListType::iterator mNextItr, mEndp; void siInit() { mPMutex.lock(); mNextItr = mPList.begin(); mEndp = mPList.end(); } ScopedIterator(ListType &wPList, Mutex &wPMutex) : mPList(wPList), mPMutex(wPMutex) { siInit(); } // Yes you can use this in a const method function and yes we are changing the Mutex and yes it is ok so use a const_cast. // ScopedIterator(ListType const &wPList) : mPList(const_cast(wPList)), mPMutex(mPList.mListLock) { siInit(); } ~ScopedIterator() { mPMutex.unlock(); } // This is meant to be used as the test statement in a for or while loop. // We always point the iterator at the next element, so that // deletion of the current element by the caller is permitted. // We also store the end element when the iteration starts, so new // elements pushed onto the back of the list during the iteration are ignored. bool next(T &var) { if (mNextItr == mEndp) return false; var = *mNextItr++; return true; } }; // An iterator to be used in for loops. template class RListIterator { typedef RList ListType; ListType &mPList; public: typename ListType::iterator mItr, mNextItr, mEndp; bool mFinished; void siInit() { mNextItr = mPList.begin(); mItr = mEndp = mPList.end(); mFinished = (mNextItr == mEndp); } RListIterator(ListType &wPList) : mPList(wPList) { siInit(); } RListIterator(ListType const &wPList) : mPList(const_cast(wPList)) { siInit(); } bool next(T &var) { if (mFinished) { return false; } mItr = mNextItr; var = *mNextItr++; mFinished = (mNextItr == mEndp); // We check now in case caller deletes end(). return true; } // Erase the current element. void erase() { devassert(mItr != mEndp); mPList.erase(mItr); mItr = mEndp; // To indicate we have already erased it. } bool next(T &var, typename ListType::iterator &itr) { // Return a regular old iterator to the user. bool result = next(var); itr = mItr; return result; } }; // A ScopedIterator wrapper specifically for RList, to be used in for loops. // The RList has the mutex built-in. template class RListIteratorThreadSafe : public ScopedIterator { public: typedef RList ListType; RListIteratorThreadSafe(ListType &wPList) : ScopedIterator(wPList,wPList.mListLock) {} // Yes you can use this in a const method and yes the Mutex is non-const but yes it is ok so use a const_cast. RListIteratorThreadSafe(ListType const &wPList) : ScopedIterator(const_cast(wPList),const_cast(wPList).mListLock) {} }; // Assumes the list is an RList which has an internal mutex. #define RN_RLIST_FOR_ALL_THREAD_SAFE(type,list,var) \ for (RListIteratorThreadSafe itr(list); itr.next(var); ) /* // This macro requires the caller to advance itr if the var is deleted. //#define RN_FOR_ALL_WITH_ITR(type,list,var,itr) \ // for (type::iterator itr = list.begin(); \ // itr == list.end() ? 0 : ((var=*itr),1); \ // itr++) */ // This macro allows deletion of the current var from the list being iterated, // because itr is advanced to the next position at the beginning of the loop, // and list iterators are defined as keeping their position even if elements are deleted. #define RN_FOR_ALL(type,list,var) \ for (type::iterator itr = (list).begin(); \ itr == (list).end() ? 0 : ((var=*itr++),1);) // Geez, the language sure botched this... #define RN_FOR_ALL_CONST(type,list,var) \ for (type::const_iterator itr = (list).begin(); \ itr == (list).end() ? 0 : ((var=*itr++),1);) /* not used #define RN_FOR_ALL_REVERSED(type,list,var) \ for (type::reverse_iterator var##_itr = (list).rbegin(); \ var##_itr == (list).rend() ? 0 : ((var=*var##_itr),1); \ var##_itr++) */ #if 0 // For your edification, these are the old functions. // Does the list contain the element? Return TRUE if so. template bool findlistrev(std::list list, T element, typename std::list::reverse_iterator *result = 0) { for (typename std::list::reverse_iterator itr = list.rbegin(); itr != list.rend(); itr++) { if (*itr == element) { if (result) *result = itr; return true; } } return false; // This did not work? // return std::find(msPCHDowns.begin(),msPCHDowns.end(),(const PDCHL1Downlink*)down) != msPCHDowns.end(); } template bool findlist(std::list list, T element, typename std::list::iterator *result = 0) { for (typename std::list::iterator itr = list.begin(); itr != list.end(); itr++) { if (*itr == element) { if (result) *result = itr; return true; } } return false; // This did not work? // return std::find(msPCHDowns.begin(),msPCHDowns.end(),(const PDCHL1Downlink*)down) != msPCHDowns.end(); } #endif #endif