1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/libraries/libmbutil/veciter.h,v 1.39 2017/01/12 14:44:05 masarati Exp $ */
2 /*
3  * MBDyn (C) is a multibody analysis code.
4  * http://www.mbdyn.org
5  *
6  * Copyright (C) 1996-2017
7  *
8  * Pierangelo Masarati	<masarati@aero.polimi.it>
9  * Paolo Mantegazza	<mantegazza@aero.polimi.it>
10  *
11  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12  * via La Masa, 34 - 20156 Milano, Italy
13  * http://www.aero.polimi.it
14  *
15  * Changing this copyright notice is forbidden.
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation (version 2 of the License).
20  *
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  */
31 
32 /* Iteratore per vettori */
33 
34 
35 #ifndef VECITER_H
36 #define VECITER_H
37 
38 #ifdef USE_MULTITHREAD
39 #include <signal.h>
40 #include "ac/spinlock.h"
41 #endif /* USE_MULTITHREAD */
42 
43 #include "myassert.h"
44 
45 /* GetFirst ritorna true ed assegna a TReturn il primo item del vettore.
46  * Si assume che il vettore contenga almeno un termine;
47  * GetNext ritorna true ed assegna a TReturn il termine successivo se esiste,
48  * altrimenti ritorna false e l'assegnamento a TReturn e' unpredictable. */
49 
50 
51 template <class T>
52 class Iter {
53 public:
~Iter(void)54 	virtual ~Iter(void) { NO_OP; };
55 	virtual bool bGetFirst(T& TReturn) const = 0;
56 	virtual bool bGetNext(T& TReturn) const = 0;
57 };
58 
59 template<class T>
60 class VecIter : public Iter<T> {
61 protected:
62 	mutable T* pStart;
63 	mutable T* pCount;
64 	unsigned iSize;
65 
66 public:
VecIter(void)67 	VecIter(void) : pStart(0), pCount(0), iSize(0) { NO_OP; };
VecIter(const T * p,unsigned i)68 	VecIter(const T* p, unsigned i) : pStart(p), pCount(p), iSize(i)
69 	{
70 		ASSERT(pStart != 0);
71 		ASSERT(iSize > 0);
72 	};
73 
~VecIter(void)74 	virtual ~VecIter(void)
75 	{
76 		NO_OP;
77 	};
78 
Init(const T * p,unsigned i)79 	void Init(const T* p, unsigned i)
80 	{
81 		ASSERT(p != NULL);
82 		ASSERT(i > 0);
83 
84 		pStart = pCount = const_cast<T *>(p);
85 		iSize = i;
86 	};
87 
bGetFirst(T & TReturn)88 	inline bool bGetFirst(T& TReturn) const
89 	{
90 		ASSERT(pStart != NULL);
91 		ASSERT(iSize > 0);
92 
93 		if (pStart == NULL) {
94 			return false;
95 		}
96 
97 		pCount = pStart;
98 		TReturn = *pStart;
99 
100 		return true;
101 	};
102 
bGetCurr(T & TReturn)103 	inline bool bGetCurr(T& TReturn) const
104 	{
105 		ASSERT(pStart != NULL);
106 		ASSERT(iSize > 0);
107 		ASSERT(pCount >= pStart);
108 
109 		if (pCount == pStart + iSize) {
110 			return false;
111 		}
112 
113 		TReturn = *pCount;
114 
115 		return true;
116 	};
117 
bGetNext(T & TReturn)118 	inline bool bGetNext(T& TReturn) const
119 	{
120 		ASSERT(pStart != NULL);
121 		ASSERT(iSize > 0);
122 		ASSERT(pCount >= pStart);
123 
124 		++pCount;
125 		if (pCount == pStart + iSize) {
126 			return false;
127 		}
128 
129 		TReturn = *pCount;
130 
131 		return true;
132 	};
133 };
134 
135 #ifdef USE_MULTITHREAD
136 /*
137  * The user's class must inherit from InUse to be used by the MT_VecIter
138  * the user must reset the inuse flag by using SetInUse() before
139  * concurrently iterating over the array; the iterator provides a
140  * helper routine for this; provide it is called only once and not
141  * concurrently.
142  */
143 class InUse {
144 private:
145 	mutable volatile AO_TS_t	inuse;
146 
147 public:
InUse(void)148 	InUse(void) : inuse(AO_TS_INITIALIZER) { NO_OP; };
~InUse(void)149 	virtual ~InUse(void) { NO_OP; };
150 
bIsInUse(void)151 	inline bool bIsInUse(void) const
152 	{
153 		/*
154 		 * If inuse is...
155 		 * 	true:	leave it as is; return false
156 		 * 	false:	make it true; return true
157 		 */
158 		/* FIXME: make it portable */
159 
160 		return (mbdyn_test_and_set(&inuse) == AO_TS_CLEAR);
161 	};
ReSetInUse()162 	inline void ReSetInUse() { AO_CLEAR(&inuse); };
163 };
164 
165 /* #define DEBUG_VECITER */
166 
167 template<class T>
168 class MT_VecIter : public VecIter<T> {
169 protected:
170 #ifdef DEBUG_VECITER
171 	mutable unsigned iCount;
172 #endif /* DEBUG_VECITER */
173 
174 public:
MT_VecIter(void)175 	MT_VecIter(void) : VecIter<T>() { NO_OP; };
MT_VecIter(const T * p,unsigned i)176 	MT_VecIter(const T* p, unsigned i) : VecIter<T>(p, i)
177 	{
178 		NO_OP;
179 	};
180 
~MT_VecIter(void)181 	virtual ~MT_VecIter(void)
182 	{
183 		NO_OP;
184 	};
185 
186 	/* NOTE: it must be called only once */
ResetAccessData(void)187 	void ResetAccessData(void)
188 	{
189 		ASSERT(VecIter<T>::pStart != NULL);
190 		ASSERT(VecIter<T>::iSize > 0);
191 
192 		for (unsigned i = 0; i < VecIter<T>::iSize; i++) {
193 			VecIter<T>::pStart[i]->ReSetInUse();
194 		}
195 	}
196 
bGetFirst(T & TReturn)197 	inline bool bGetFirst(T& TReturn) const
198 	{
199 		ASSERT(VecIter<T>::pStart != NULL);
200 		ASSERT(VecIter<T>::iSize > 0);
201 
202 #ifdef DEBUG_VECITER
203 		iCount = 0;
204 #endif /* DEBUG_VECITER */
205 
206 		VecIter<T>::pCount = VecIter<T>::pStart - 1;
207 
208 		return bGetNext(TReturn);
209 	};
210 
bGetCurr(T & TReturn)211 	inline bool bGetCurr(T& TReturn) const
212 	{
213 		ASSERT(VecIter<T>::pStart != NULL);
214 		ASSERT(VecIter<T>::iSize > 0);
215 		ASSERT(VecIter<T>::pCount >= VecIter<T>::pStart - 1 &&
216 			VecIter<T>::pCount < VecIter<T>::pStart + VecIter<T>::iSize);
217 
218 		if (VecIter<T>::pCount == VecIter<T>::pStart + VecIter<T>::iSize) {
219 			return false;
220 		}
221 
222 		TReturn = *VecIter<T>::pCount;
223 		/* NOTE: of course, by definition it's already in use */
224 
225 		return true;
226 	};
227 
bGetNext(T & TReturn)228 	inline bool bGetNext(T& TReturn) const
229 	{
230 		ASSERT(VecIter<T>::pStart != NULL);
231 		ASSERT(VecIter<T>::iSize > 0);
232 		ASSERT(VecIter<T>::pCount >= VecIter<T>::pStart - 1 &&
233 			VecIter<T>::pCount < VecIter<T>::pStart + VecIter<T>::iSize);
234 
235 		for (VecIter<T>::pCount++;
236 			VecIter<T>::pCount < VecIter<T>::pStart + VecIter<T>::iSize;
237 			VecIter<T>::pCount++) {
238 			if ((*VecIter<T>::pCount)->bIsInUse()) {
239 				TReturn = *VecIter<T>::pCount;
240 #ifdef DEBUG_VECITER
241 				iCount++;
242 #endif /* DEBUG_VECITER */
243 				return true;
244 			}
245 		}
246 
247 #ifdef DEBUG_VECITER
248 		silent_cerr("[" << pthread_self() << "]: total=" << iCount
249 				<< std::endl);
250 #endif /* DEBUG_VECITER */
251 		return false;
252 	};
253 };
254 
255 #endif /* USE_MULTITHREAD */
256 
257 #endif /* VECITER_H */
258