mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-10-23 07:42:01 +00:00
214 lines
6.9 KiB
C++
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
|