AERA
pipe.tpl.cpp
1 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
2 //_/_/
3 //_/_/ AERA
4 //_/_/ Autocatalytic Endogenous Reflective Architecture
5 //_/_/
6 //_/_/ Copyright (c) 2018-2025 Jeff Thompson
7 //_/_/ Copyright (c) 2018-2025 Kristinn R. Thorisson
8 //_/_/ Copyright (c) 2018-2025 Icelandic Institute for Intelligent Machines
9 //_/_/ http://www.iiim.is
10 //_/_/
11 //_/_/ Copyright (c) 2010-2012 Eric Nivel, Thor List
12 //_/_/ Center for Analysis and Design of Intelligent Agents
13 //_/_/ Reykjavik University, Menntavegur 1, 102 Reykjavik, Iceland
14 //_/_/ http://cadia.ru.is
15 //_/_/
16 //_/_/ Part of this software was developed by Eric Nivel
17 //_/_/ in the HUMANOBS EU research project, which included
18 //_/_/ the following parties:
19 //_/_/
20 //_/_/ Autonomous Systems Laboratory
21 //_/_/ Technical University of Madrid, Spain
22 //_/_/ http://www.aslab.org/
23 //_/_/
24 //_/_/ Communicative Machines
25 //_/_/ Edinburgh, United Kingdom
26 //_/_/ http://www.cmlabs.com/
27 //_/_/
28 //_/_/ Istituto Dalle Molle di Studi sull'Intelligenza Artificiale
29 //_/_/ University of Lugano and SUPSI, Switzerland
30 //_/_/ http://www.idsia.ch/
31 //_/_/
32 //_/_/ Institute of Cognitive Sciences and Technologies
33 //_/_/ Consiglio Nazionale delle Ricerche, Italy
34 //_/_/ http://www.istc.cnr.it/
35 //_/_/
36 //_/_/ Dipartimento di Ingegneria Informatica
37 //_/_/ University of Palermo, Italy
38 //_/_/ http://diid.unipa.it/roboticslab/
39 //_/_/
40 //_/_/
41 //_/_/ --- HUMANOBS Open-Source BSD License, with CADIA Clause v 1.0 ---
42 //_/_/
43 //_/_/ Redistribution and use in source and binary forms, with or without
44 //_/_/ modification, is permitted provided that the following conditions
45 //_/_/ are met:
46 //_/_/ - Redistributions of source code must retain the above copyright
47 //_/_/ and collaboration notice, this list of conditions and the
48 //_/_/ following disclaimer.
49 //_/_/ - Redistributions in binary form must reproduce the above copyright
50 //_/_/ notice, this list of conditions and the following disclaimer
51 //_/_/ in the documentation and/or other materials provided with
52 //_/_/ the distribution.
53 //_/_/
54 //_/_/ - Neither the name of its copyright holders nor the names of its
55 //_/_/ contributors may be used to endorse or promote products
56 //_/_/ derived from this software without specific prior
57 //_/_/ written permission.
58 //_/_/
59 //_/_/ - CADIA Clause: The license granted in and to the software
60 //_/_/ under this agreement is a limited-use license.
61 //_/_/ The software may not be used in furtherance of:
62 //_/_/ (i) intentionally causing bodily injury or severe emotional
63 //_/_/ distress to any person;
64 //_/_/ (ii) invading the personal privacy or violating the human
65 //_/_/ rights of any person; or
66 //_/_/ (iii) committing or preparing for any act of war.
67 //_/_/
68 //_/_/ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
69 //_/_/ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
70 //_/_/ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
71 //_/_/ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
72 //_/_/ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
73 //_/_/ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
74 //_/_/ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
75 //_/_/ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
76 //_/_/ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
77 //_/_/ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
78 //_/_/ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
79 //_/_/ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
80 //_/_/ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
81 //_/_/ OF SUCH DAMAGE.
82 //_/_/
83 //_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
84 
85 #include <memory.h>
86 
87 
88 namespace core {
89 
90 #ifdef PIPE_1
91 template<typename T, uint32 _S> Pipe11<T, _S>::Pipe11() : Semaphore(0, 65535) {
92 
93  head_ = tail_ = -1;
94  first_ = last_ = new Block(NULL);
95  spare_ = NULL;
96 }
97 
98 template<typename T, uint32 _S> Pipe11<T, _S>::~Pipe11() {
99 
100  delete first_;
101  if (spare_)
102  delete spare_;
103 }
104 
105 template<typename T, uint32 _S> inline void Pipe11<T, _S>::_clear() { // leaves spare_ as is
106 
107  enter();
108  reset();
109  if (first_->next_)
110  delete first_->next_;
111  first_->next_ = NULL;
112  head_ = tail_ = -1;
113  leave();
114 }
115 
116 template<typename T, uint32 _S> inline T Pipe11<T, _S>::_pop() {
117 
118  T t = first_->buffer_[head_];
119  if (++head_ == _S) {
120 
121  enter();
122  if (first_ == last_)
123  head_ = tail_ = -1; // stay in the same block; next push will reset head_ and tail_ to 0
124  else {
125 
126  if (!spare_) {
127 
128  spare_ = first_;
129  first_ = first_->next_;
130  spare_->next_ = NULL;
131  } else {
132 
133  Block *b = first_->next_;
134  first_->next_ = NULL;
135  delete first_;
136  first_ = b;
137  }
138  head_ = 0;
139  }
140  leave();
141  }
142  return t;
143 }
144 
145 template<typename T, uint32 _S> inline void Pipe11<T, _S>::push(T &t) {
146 
147  enter();
148  if (++tail_ == 0)
149  head_ = 0;
150  uint32 index = tail_;
151  if (tail_ == _S) {
152 
153  if (spare_) {
154 
155  last_->next_ = spare_;
156  last_ = spare_;
157  last_->next_ = NULL;
158  spare_ = NULL;
159  } else
160  last_ = new Block(last_);
161  tail_ = 0;
162  index = tail_;
163  }
164  leave();
165 
166  last_->buffer_[index] = t;
167  release();
168 }
169 
170 template<typename T, uint32 _S> inline T Pipe11<T, _S>::pop() {
171 
172  Semaphore::acquire();
173  return _pop();
174 }
175 
176 template<typename T, uint32 _S> inline void Pipe11<T, _S>::clear() {
177 
178  _clear();
179 }
180 
182 
183 template<typename T, uint32 _S> Pipe1N<T, _S>::Pipe1N() {
184 }
185 
186 template<typename T, uint32 _S> Pipe1N<T, _S>::~Pipe1N() {
187 }
188 
189 template<typename T, uint32 _S> void Pipe1N<T, _S>::clear() {
190 
191  popCS_.enter();
192  Pipe11<T, _S>::_clear();
193  popCS_.leave();
194 }
195 
196 template<typename T, uint32 _S> T Pipe1N<T, _S>::pop() {
197 
198  Semaphore::acquire();
199  popCS_.enter();
200  T t = Pipe11<T, _S>::_pop();
201  popCS_.leave();
202  return t;
203 }
204 
206 
207 template<typename T, uint32 _S> PipeN1<T, _S>::PipeN1() {
208 }
209 
210 template<typename T, uint32 _S> PipeN1<T, _S>::~PipeN1() {
211 }
212 
213 template<typename T, uint32 _S> void PipeN1<T, _S>::clear() {
214 
215  pushCS_.enter();
216  Pipe11<T, _S>::_clear();
217  pushCS_.leave();
218 }
219 
220 template<typename T, uint32 _S> void PipeN1<T, _S>::push(T &t) {
221 
222  pushCS_.enter();
223  Pipe11<T, _S>::push(t);
224  pushCS_.leave();
225 }
226 
228 
229 template<typename T, uint32 _S> PipeNN<T, _S>::PipeNN() {
230 }
231 
232 template<typename T, uint32 _S> PipeNN<T, _S>::~PipeNN() {
233 }
234 
235 template<typename T, uint32 _S> void PipeNN<T, _S>::clear() {
236 
237  pushCS_.enter();
238  popCS_.enter();
239  Pipe11<T, _S>::_clear();
240  popCS_.leave();
241  pushCS_.leave();
242 }
243 
244 template<typename T, uint32 _S> void PipeNN<T, _S>::push(T &t) {
245 
246  pushCS_.enter();
247  Pipe11<T, _S>::push(t);
248  pushCS_.leave();
249 }
250 
251 template<typename T, uint32 _S> T PipeNN<T, _S>::pop(bool waitForItem) {
252 
253  if (waitForItem)
254  Semaphore::acquire();
255  else {
256  // Use 0 timeout.
257  if (Semaphore::acquire(0))
258  // A timeout means there are no items.
259  return NULL;
260  }
261  popCS_.enter();
262  T t = Pipe11<T, _S>::_pop();
263  popCS_.leave();
264  return t;
265 }
266 #elif defined PIPE_2
267 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> Pipe<T, _S, Head, Tail, P, Push, Pop>::Pipe() : Semaphore(0, 1) {
268 
269  head_ = -1;
270  tail_ = 0;
271 
272  waitingList_ = 0;
273 
274  first_ = last_ = new Block(NULL);
275  spare_ = new Block(NULL);
276 
277  _push = new Push<T, _S, P>(*(P *)this);
278  _pop = new Pop<T, _S, P>(*(P *)this);
279 }
280 
281 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> Pipe<T, _S, Head, Tail, P, Push, Pop>::~Pipe() {
282 
283  delete first_;
284  if (spare_)
285  delete spare_;
286  delete _push;
287  delete _pop;
288 }
289 
290 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> inline void Pipe<T, _S, Head, Tail, P, Push, Pop>::shrink() {
291 
292  if (!spare_) {
293 
294  spare_ = first_;
295  first_ = first_->next_;
296  spare_->next_ = NULL;
297  } else {
298 
299  Block *b = first_->next_;
300  first_->next_ = NULL;
301  delete first_;
302  first_ = b;
303  }
304  head_ = -1;
305 }
306 
307 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> inline void Pipe<T, _S, Head, Tail, P, Push, Pop>::grow() {
308 
309  if (spare_) {
310 
311  last_->next_ = spare_;
312  last_ = spare_;
313  last_->next_ = NULL;
314  spare_ = NULL;
315  } else
316  last_ = new Block(last_);
317  tail_ = 0;
318 }
319 
320 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> inline void Pipe<T, _S, Head, Tail, P, Push, Pop>::push(T &t) {
321 
322  (*_push)(t);
323 }
324 
325 template<typename T, uint32 _S, typename Head, typename Tail, class P, template<typename, uint32, class> class Push, template<typename, uint32, class> class Pop> inline T Pipe<T, _S, Head, Tail, P, Push, Pop>::pop() {
326 
327  return (*_pop)();
328 }
329 
331 
332 template<class Pipe> PipeFunctor<Pipe>::PipeFunctor(Pipe &p) : pipe(p) {
333 }
334 
336 
337 template<typename T, uint32 _S, class Pipe> Push1<T, _S, Pipe>::Push1(Pipe &p) : PipeFunctor<Pipe>(p) {
338 }
339 
340 template<typename T, uint32 _S, class Pipe> void Push1<T, _S, Pipe>::operator ()(T &t) {
341 
342  pipe.last_->buffer_[pipe.tail_] = t;
343 
344  if (++pipe.tail_ == (int32)_S)
345  pipe.grow();
346 
347  int32 count = Atomic::Decrement32(&pipe.waitingList_);
348  if (count >= 0) // at least one reader is waiting
349  pipe.release(); // unlock one reader
350 }
351 
353 
354 template<typename T, uint32 _S, class Pipe> PushN<T, _S, Pipe>::PushN(Pipe &p) : PipeFunctor<Pipe>(p), Semaphore(0, 1) {
355 }
356 
357 template<typename T, uint32 _S, class Pipe> void PushN<T, _S, Pipe>::operator ()(T &t) {
358 
359 check_tail: int32 tail = Atomic::Increment32(&pipe.tail_) - 1;
360 
361  if (tail < (int32)_S)
362  pipe.last_->buffer_[tail] = t;
363  else if (tail == (int32)_S) {
364 
365  pipe.grow(); // tail set to 0
366 
367  pipe.last_->buffer_[pipe.tail_++] = t;
368 
369  release(); // unlock writers
370  acquire(); // make sure the sem falls back to 0
371  } else { // tail>_S: pipe.last_ and pipe.tail_ are being changed
372 
373  acquire(); // wait
374  release(); // unlock other writers
375  goto check_tail;
376  }
377 
378  int32 count = Atomic::Decrement32(&pipe.waitingList_);
379  if (count >= 0) // at least one reader is waiting
380  pipe.release(); // unlock one reader
381 }
382 
384 
385 template<typename T, uint32 _S, class Pipe> Pop1<T, _S, Pipe>::Pop1(Pipe &p) : PipeFunctor<Pipe>(p) {
386 }
387 
388 template<typename T, uint32 _S, class Pipe> T Pop1<T, _S, Pipe>::operator ()() {
389 
390  int32 count = Atomic::Increment32(&pipe.waitingList_);
391  if (count > 0) // no free lunch
392  pipe.acquire(); // wait for a push
393 
394  if (pipe.head_ == (int32)_S - 1)
395  pipe.shrink();
396 
397  T t = pipe.first_->buffer_[++pipe.head_];
398 
399  return t;
400 }
401 
403 
404 template<typename T, uint32 _S, class Pipe> PopN<T, _S, Pipe>::PopN(Pipe &p) : PipeFunctor<Pipe>(p), Semaphore(0, 1) {
405 }
406 
407 template<typename T, uint32 _S, class Pipe> T PopN<T, _S, Pipe>::operator ()() {
408 
409  int32 count = Atomic::Increment32(&pipe.waitingList_);
410  if (count > 0) // no free lunch
411  pipe.acquire(); // wait for a push
412 
413 check_head: int32 head = Atomic::Increment32(&pipe.head_);
414  if (head < (int32)_S)
415  return pipe.first_->buffer_[head];
416 
417  if (head == (int32)_S) {
418 
419  pipe.shrink(); // head set to -1
420 
421  release(); // unlock readers
422  acquire(); // make sure the sem falls back to 0
423 
424  return pipe.first_->buffer_[++pipe.head_];
425  } else { // head>_S: pipe.first_ and pipe.head_ are being changed
426 
427  acquire(); // wait
428  release(); // unlock other readers
429  goto check_head;
430  }
431 }
432 
434 
435 template<typename T, uint32 S> Pipe11<T, S>::Pipe11() : Pipe<T, S, int32, int32, Pipe11<T, S>, Push1, Pop1>() {
436 }
437 
438 template<typename T, uint32 S> Pipe11<T, S>::~Pipe11() {
439 }
440 
442 
443 template<typename T, uint32 S> Pipe1N<T, S>::Pipe1N() : Pipe<T, S, int32, int32 volatile, Pipe1N, Push1, PopN>() {
444 }
445 
446 template<typename T, uint32 S> Pipe1N<T, S>::~Pipe1N() {
447 }
448 
450 
451 template<typename T, uint32 S> PipeN1<T, S>::PipeN1() : Pipe<T, S, int32 volatile, int32, PipeN1, PushN, Pop1>() {
452 }
453 
454 template<typename T, uint32 S> PipeN1<T, S>::~PipeN1() {
455 }
456 
458 
459 template<typename T, uint32 S> PipeNN<T, S>::PipeNN() : Pipe<T, S, int32 volatile, int32 volatile, PipeNN, PushN, PopN>() {
460 }
461 
462 template<typename T, uint32 S> PipeNN<T, S>::~PipeNN() {
463 }
464 #endif
465 }