Files
openbts/GPRS/RList.h
2014-07-16 23:57:22 +02:00

214 lines
6.9 KiB
C++

/*
* 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 <list>
#include "GPRSInternal.h" // For devassert
// A list with random access too.
template<class T>
class RList : public std::list<T> {
typedef typename std::list<T>::iterator itr_t;
typedef typename std::list<T> 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<T>::push_back(val); }
//void remove_safely(T&val) { std::list<T>::remove(val); }
};
// Like RList but add an internal Mutex so it can auto-lock for multi-threads using RlistIteratorThreadSafe.
template<class T>
class RListThreadSafe : RList<T> {
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<T>::push_back(val);
}
void remove_safely(T&val) {
ScopedLock lock(mListLock);
std::list<T>::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<T> mylist; Mutex mymutex; for (ScopedIterator<T,list<T> >(mylist,mymutex); next(var);)
template<class T, class ListType = RList<T> >
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<ListType&>(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 T>
class RListIterator
{
typedef RList<T> 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<ListType&>(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 T>
class RListIteratorThreadSafe : public ScopedIterator<T>
{ public:
typedef RList<T> ListType;
RListIteratorThreadSafe(ListType &wPList) : ScopedIterator<T>(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<T>(const_cast<ListType&>(wPList),const_cast<ListType&>(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<type> 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<class T>
bool findlistrev(std::list<T> list, T element, typename std::list<T>::reverse_iterator *result = 0) {
for (typename std::list<T>::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<class T>
bool findlist(std::list<T> list, T element, typename std::list<T>::iterator *result = 0) {
for (typename std::list<T>::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