blob: a6c6f32c5cc49176b0a6bb8874e88abd79fe3d5c [file] [log] [blame]
Alexandre Lisionddd731e2014-01-31 11:50:08 -05001// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
2//
3// This file is part of GNU uCommon C++.
4//
5// GNU uCommon C++ is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published
7// by the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// GNU uCommon C++ is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
17
18/**
19 * Threadsafe object containers. This is used to better define
20 * object containers and manipulating classes which can be presumed to be
21 * fully threadsafe and thread-aware. This has to be defined separately
22 * to assure correct order of preceeding headers as well as to better
23 * organize the library for clarity. Most of these classes and templates
24 * work with classes derived from Object and LinkedObject and make use of
25 * conditional for time constrained acquisition of managed objects.
26 * @file ucommon/containers.h
27 */
28
29#ifndef _UCOMMON_CONTAINERS_H_
30#define _UCOMMON_CONTAINERS_H_
31
32#ifndef _UCOMMON_CONFIG_H_
33#include <ucommon/platform.h>
34#endif
35
36#ifndef _UCOMMON_PROTOCOLS_H_
37#include <ucommon/protocols.h>
38#endif
39
40#ifndef _UCOMMON_LINKED_H_
41#include <ucommon/linked.h>
42#endif
43
44#ifndef _UCOMMON_MEMORY_H_
45#include <ucommon/memory.h>
46#endif
47
48#ifndef _UCOMMON_THREAD_H_
49#include <ucommon/thread.h>
50#endif
51
52NAMESPACE_UCOMMON
53
54/**
55 * Linked allocator helper for linked_allocator template. This is used
56 * to alloc an array of typed objects tied to a free list in a single
57 * operation.
58 * @author David Sugar <dyfet@gnutelephony.org>
59 */
60class __EXPORT LinkedAllocator : private Conditional
61{
62protected:
63 LinkedObject *freelist;
64
65 LinkedAllocator();
66
67 LinkedObject *get(void);
68
69 LinkedObject *get(timeout_t timeout);
70
71 void release(LinkedObject *node);
72
73public:
74 /**
75 * Test if there is still objects in the free list.
76 * @return true if there are objects.
77 */
78 operator bool();
79
80 /**
81 * Test if the free list is empty.
82 * @return true if the free list is empty.
83 */
84 bool operator!();
85};
86
87/**
88 * A thread-safe buffer for serializing and streaming class data. While
89 * the queue and stack operate by managing lists of reference pointers to
90 * objects of various mixed kind, the buffer holds physical copies of objects
91 * that being passed through it, and all must be the same size. For this
92 * reason the buffer is normally used through the bufferof<type> template
93 * rather than stand-alone. The buffer is accessed in fifo order.
94 * @author David Sugar <dyfet@gnutelephony.org>
95 */
96class __EXPORT Buffer : protected Conditional
97{
98private:
99 size_t bufsize, objsize;
100 caddr_t buf, head, tail;
101 unsigned objcount, limit;
102
103protected:
104 /**
105 * Create a buffer to hold a series of objects.
106 * @param size of each object in buffer.
107 * @param count of objects in the buffer.
108 */
109 Buffer(size_t typesize, size_t count);
110
111 /**
112 * Deallocate buffer and unblock any waiting threads.
113 */
114 virtual ~Buffer();
115
116 /**
117 * Get the next object from the buffer.
118 * @param timeout to wait when buffer is empty in milliseconds.
119 * @return pointer to next object in the buffer or NULL if timed out.
120 */
121 void *get(timeout_t timeout);
122
123 /**
124 * Get the next object from the buffer. This blocks until an object
125 * becomes available.
126 * @return pointer to next object from buffer.
127 */
128 void *get(void);
129
130 /**
131 * Put (copy) an object into the buffer. This blocks while the buffer
132 * is full.
133 * @param data to copy into the buffer.
134 */
135 void put(void *data);
136
137 /**
138 * Put (copy) an object into the buffer.
139 * @param data to copy into the buffer.
140 * @param timeout to wait if buffer is full.
141 * @return true if copied, false if timed out while full.
142 */
143 bool put(void *data, timeout_t timeout);
144
145 /**
146 * Release must be called when we get an object from the buffer. This
147 * is because the pointer we return is a physical pointer to memory
148 * that is part of the buffer. The object we get cannot be removed or
149 * the memory modified while the object is being used.
150 */
151 void release(void);
152
153 /**
154 * Copy the next object from the buffer. This blocks until an object
155 * becomes available. Buffer is auto-released.
156 * @param data pointer to copy into.
157 */
158 void copy(void *data);
159
160 /**
161 * Copy the next object from the buffer. Buffer is auto-released.
162 * @param data pointer to copy into.
163 * @param timeout to wait when buffer is empty in milliseconds.
164 * @return true if object copied, or false if timed out.
165 */
166 bool copy(void *data, timeout_t timeout);
167
168 /**
169 * Peek at pending data in buffer. This returns a pointer to
170 * objects relative to the head. In effect it is the same as
171 * get() for item = 0.
172 * @param item to examine in buffer.
173 * @return pointer to item or NULL if invalid item number.
174 */
175 void *peek(unsigned item);
176
177 virtual void *invalid(void) const;
178
179public:
180 /**
181 * Get the size of the buffer.
182 * @return size of the buffer.
183 */
184 unsigned size(void);
185
186 /**
187 * Get the number of objects in the buffer currently.
188 * @return number of objects buffered.
189 */
190 unsigned count(void);
191
192 /**
193 * Test if there is data waiting in the buffer.
194 * @return true if buffer has data.
195 */
196 operator bool();
197
198 /**
199 * Test if the buffer is empty.
200 * @return true if the buffer is empty.
201 */
202 bool operator!();
203};
204
205/**
206 * Manage a thread-safe queue of objects through reference pointers. This
207 * can be particularly interesting when used to enqueue/dequeue reference
208 * counted managed objects. Thread-safe access is managed through a
209 * conditional. Both lifo and fifo forms of queue access may be used. A
210 * pool of self-managed member objects are used to operate the queue. This
211 * queue is optimized for fifo access; while lifo is supported, it will be
212 * slow. If you need primarily lifo, you should use stack instead.
213 * @author David Sugar <dyfet@gnutelephony.org>
214 */
215class __EXPORT Queue : protected OrderedIndex, protected Conditional
216{
217private:
218 mempager *pager;
219 LinkedObject *freelist;
220 size_t used;
221
222 class __LOCAL member : public OrderedObject
223 {
224 public:
225 member(Queue *q, ObjectProtocol *obj);
226 ObjectProtocol *object;
227 };
228
229 friend class member;
230
231protected:
232 size_t limit;
233
234 virtual ObjectProtocol *invalid(void) const;
235
236public:
237 /**
238 * Create a queue that uses a memory pager for internally managed
239 * member objects for a specified maximum number of object pointers.
240 * @param pager to use for internal member object or NULL to use heap.
241 * @param number of pointers that can be in the queue or 0 for unlimited.
242 * size limit.
243 */
244 Queue(mempager *pager = NULL, size_t number = 0);
245
246 /**
247 * Destroy queue. If no mempager is used, then frees heap.
248 */
249 ~Queue();
250
251 /**
252 * Remove a specific object pointer for the queue. This can remove
253 * a member from any location in the queue, whether beginning, end, or
254 * somewhere in the middle. This also releases the object.
255 * @param object to remove.
256 * @return true if object was removed, false if not found.
257 */
258 bool remove(ObjectProtocol *object);
259
260 /**
261 * Post an object into the queue by it's pointer. This can wait for
262 * a specified timeout if the queue is full, for example, for another
263 * thread to remove an object pointer. This also retains the object.
264 * @param object to post.
265 * @param timeout to wait if queue is full in milliseconds.
266 * @return true if object posted, false if queue full and timeout expired.
267 */
268 bool post(ObjectProtocol *object, timeout_t timeout = 0);
269
270 /**
271 * Examine pending existing object in queue. Does not remove it.
272 * @param number of elements back.
273 * @return object in queue or NULL if invalid value.
274 */
275 ObjectProtocol *get(unsigned offset = 0);
276
277 /**
278 * Get and remove last object posted to the queue. This can wait for
279 * a specified timeout of the queue is empty. The object is still
280 * retained and must be released or deleted by the receiving function.
281 * @param timeout to wait if empty in milliseconds.
282 * @return object from queue or NULL if empty and timed out.
283 */
284 ObjectProtocol *fifo(timeout_t timeout = 0);
285
286 /**
287 * Get and remove first object posted to the queue. This can wait for
288 * a specified timeout of the queue is empty. The object is still
289 * retained and must be released or deleted by the receiving function.
290 * @param timeout to wait if empty in milliseconds.
291 * @return object from queue or NULL if empty and timed out.
292 */
293 ObjectProtocol *lifo(timeout_t timeout = 0);
294
295 /**
296 * Get number of object points currently in the queue.
297 * @return number of objects in queue.
298 */
299 size_t count(void);
300};
301
302/**
303 * Manage a thread-safe stack of objects through reference pointers. This
304 * Thread-safe access is managed through a conditional. This differs from
305 * the queue in lifo mode because delinking the last object is immediate,
306 * and because it has much less overhead. A pool of self-managed
307 * member objects are used to operate the stack.
308 * @author David Sugar <dyfet@gnutelephony.org>
309 */
310class __EXPORT Stack : protected Conditional
311{
312private:
313 LinkedObject *freelist, *usedlist;
314 mempager *pager;
315 size_t used;
316
317 class __LOCAL member : public LinkedObject
318 {
319 public:
320 member(Stack *s, ObjectProtocol *obj);
321 ObjectProtocol *object;
322 };
323
324 friend class member;
325
326protected:
327 size_t limit;
328
329 virtual ObjectProtocol *invalid(void) const;
330
331public:
332 /**
333 * Create a stack that uses a memory pager for internally managed
334 * member objects for a specified maximum number of object pointers.
335 * @param pager to use for internal member object or NULL to use heap.
336 * @param number of pointers that can be in the stack or 0 if unlimited.
337 */
338 Stack(mempager *pager = NULL, size_t number = 0);
339
340 /**
341 * Destroy queue. If no pager is used, then frees heap.
342 */
343 virtual ~Stack();
344
345 /**
346 * Remove a specific object pointer for the queue. This can remove
347 * a member from any location in the queue, whether beginning, end, or
348 * somewhere in the middle. This also releases the object.
349 * @param object to remove.
350 * @return true if object was removed, false if not found.
351 */
352 bool remove(ObjectProtocol *object);
353
354 /**
355 * Push an object into the stack by it's pointer. This can wait for
356 * a specified timeout if the stack is full, for example, for another
357 * thread to remove an object pointer. This also retains the object.
358 * @param object to push.
359 * @param timeout to wait if stack is full in milliseconds.
360 * @return true if object pushed, false if stack full and timeout expired.
361 */
362 bool push(ObjectProtocol *object, timeout_t timeout = 0);
363
364 /**
365 * Get and remove last object pushed on the stack. This can wait for
366 * a specified timeout of the stack is empty. The object is still
367 * retained and must be released or deleted by the receiving function.
368 * @param timeout to wait if empty in milliseconds.
369 * @return object pulled from stack or NULL if empty and timed out.
370 */
371 ObjectProtocol *pull(timeout_t timeout = 0);
372
373 /**
374 * Examine an existing object on the stack.
375 * @param offset to stack entry.
376 * @return object examined.
377 */
378 ObjectProtocol *get(unsigned offset = 0);
379
380 /**
381 * Get number of object points currently in the stack.
382 * @return number of objects in stack.
383 */
384 size_t count(void);
385
386 const ObjectProtocol *peek(timeout_t timeout = 0);
387};
388
389/**
390 * Linked allocator template to gather linked objects. This allocates the
391 * object pool in a single array as a single heap allocation, and releases
392 * the whole pool with a single delete when done. It is also threadsafe.
393 * The types used must be derived of LinkedObject.
394 * @author David Sugar <dyfet@gnutelephony.org>
395 */
396template <class T>
397class linked_allocator : public LinkedAllocator
398{
399private:
400 T* array;
401
402public:
403 inline linked_allocator(size_t size) : LinkedAllocator() {
404 array = new T[size];
405 for(unsigned i = 0; i < size; ++i)
406 array[i].enlist(&freelist);
407 }
408
409 ~linked_allocator()
410 {delete[] array;};
411
412 inline T *get(void)
413 {return static_cast<T *>(LinkedAllocator::get());};
414
415 inline T *get(timeout_t timeout)
416 {return static_cast<T *>(LinkedAllocator::get(timeout));};
417
418 inline void release(T *node)
419 {LinkedAllocator::release(node);};
420};
421
422/**
423 * A templated typed class for buffering of objects. This operates as a
424 * fifo buffer of typed objects which are physically copied into the buffer.
425 * The objects that are buffered are accessed from allocated buffer space.
426 * As designed this may be used with multiple producer threads and one
427 * consumer thread. To use multiple consumers, one can copy the typed object
428 * from the buffer through the get pointer and then call release. The
429 * copied object can then be used safely. This is what the copy method is
430 * used for.
431 * @author David Sugar <dyfet@gnutelephony.org>
432 */
433template<class T>
434class bufferof : public Buffer
435{
436public:
437 /**
438 * Create a buffer to hold a series of typed objects.
439 * @param count of typed objects in the buffer.
440 */
441 inline bufferof(unsigned capacity) :
442 Buffer(sizeof(T), capacity) {};
443
444 /**
445 * Get the next typed object from the buffer. This blocks until an object
446 * becomes available.
447 * @return pointer to next typed object from buffer.
448 */
449 inline T *get(void)
450 {return static_cast<T*>(get());};
451
452 /**
453 * Get the next typed object from the buffer.
454 * @param timeout to wait when buffer is empty in milliseconds.
455 * @return pointer to next typed object in the buffer or NULL if timed out.
456 */
457 inline T *get(timeout_t timeout)
458 {return static_cast<T*>(get(timeout));};
459
460 /**
461 * Put (copy) a typed object into the buffer. This blocks while the buffer
462 * is full.
463 * @param object to copy into the buffer.
464 */
465 inline void put(T *object)
466 {put(object);};
467
468 /**
469 * Put (copy) an object into the buffer.
470 * @param object to copy into the buffer.
471 * @param timeout to wait if buffer is full.
472 * @return true if copied, false if timed out while full.
473 */
474 inline bool put(T *object, timeout_t timeout)
475 {return put(object, timeout);};
476
477 /**
478 * Copy the next typed object from the buffer. This blocks until an object
479 * becomes available.
480 * @param object pointer to copy typed object into.
481 */
482 inline void copy(T *object)
483 {copy(object);};
484
485 /**
486 * Copy the next typed object from the buffer.
487 * @param object pointer to copy typed object into.
488 * @param timeout to wait when buffer is empty in milliseconds.
489 * @return true if object copied, or false if timed out.
490 */
491 inline bool get(T *object, timeout_t timeout)
492 {return copy(object, timeout);};
493
494 /**
495 * Examine past item in the buffer. This is a typecast of the peek
496 * operation.
497 * @param item in buffer.
498 * @return item pointer if valid or NULL.
499 */
500 inline const T& at(unsigned item)
501 {return static_cast<const T&>(Buffer::peek(item));};
502
503 /**
504 * Examine past item in the buffer. This is a typecast of the peek
505 * operation.
506 * @param item in buffer.
507 * @return item pointer if valid or NULL.
508 */
509 inline T&operator[](unsigned item)
510 {return static_cast<T&>(Buffer::peek(item));};
511
512 inline T* operator()(unsigned offset = 0)
513 {return static_cast<T*>(Buffer::peek(offset));}
514};
515
516/**
517 * A templated typed class for thread-safe stack of object pointers. This
518 * allows one to use the stack class in a typesafe manner for a specific
519 * object type derived from Object rather than generically for any derived
520 * object class.
521 * @author David Sugar <dyfet@gnutelephony.org>
522 */
523template<class T>
524class stackof : public Stack
525{
526public:
527 /**
528 * Create templated stack of typed objects.
529 * @param memory pool for internal use of stack.
530 * @param size of stack to construct. Uses 0 if no size limit.
531 */
532 inline stackof(mempager *memory, size_t size = 0) : Stack(memory, size) {};
533
534 /**
535 * Remove a specific typed object pointer for the stack. This can remove
536 * a member from any location in the stack, whether beginning, end, or
537 * somewhere in the middle. This releases the object.
538 * @param object to remove.
539 * @return true if object was removed, false if not found.
540 */
541 inline bool remove(T *object)
542 {return Stack::remove(object);};
543
544 /**
545 * Push a typed object into the stack by it's pointer. This can wait for
546 * a specified timeout if the queue is full, for example, for another
547 * thread to remove an object pointer. This retains the object.
548 * @param object to push.
549 * @param timeout to wait if queue is full in milliseconds.
550 * @return true if object pushed, false if queue full and timeout expired.
551 */
552 inline bool push(T *object, timeout_t timeout = 0)
553 {return Stack::push(object);};
554
555 /**
556 * Get and remove last typed object posted to the stack. This can wait for
557 * a specified timeout of the stack is empty. The object is still retained
558 * and must be released or deleted by the receiving function.
559 * @param timeout to wait if empty in milliseconds.
560 * @return object from queue or NULL if empty and timed out.
561 */
562 inline T *pull(timeout_t timeout = 0)
563 {return static_cast<T *>(Stack::pull(timeout));};
564
565 /**
566 * Examine last typed object posted to the stack. This can wait for
567 * a specified timeout of the stack is empty.
568 * @param timeout to wait if empty in milliseconds.
569 * @return object in queue or NULL if empty and timed out.
570 */
571 inline const T *peek(timeout_t timeout = 0)
572 {return static_cast<const T *>(Stack::peek(timeout));};
573
574 inline T* operator()(unsigned offset = 0)
575 {return static_cast<T*>(Stack::get(offset));}
576
577 /**
578 * Examine past item in the stack. This is a typecast of the peek
579 * operation.
580 * @param offset in stack.
581 * @return item pointer if valid or NULL.
582 */
583 inline const T& at(unsigned offset = 0)
584 {return static_cast<const T&>(Stack::get(offset));};
585
586 /**
587 * Examine past item in the stack. This is a typecast of the peek
588 * operation.
589 * @param offset in stack.
590 * @return item pointer if valid or NULL.
591 */
592 inline const T& operator[](unsigned offset)
593 {return static_cast<T&>(Stack::get(offset));};
594
595};
596
597/**
598 * A templated typed class for thread-safe queue of object pointers. This
599 * allows one to use the queue class in a typesafe manner for a specific
600 * object type derived from Object rather than generically for any derived
601 * object class.
602 * @author David Sugar <dyfet@gnutelephony.org>
603 */
604template<class T>
605class queueof : public Queue
606{
607public:
608 /**
609 * Create templated queue of typed objects.
610 * @param memory pool for internal use by queue.
611 * @param size of queue to construct. Uses 0 if no size limit.
612 */
613 inline queueof(mempager *memory, size_t size = 0) : Queue(memory, size) {};
614
615 /**
616 * Remove a specific typed object pointer for the queue. This can remove
617 * a member from any location in the queue, whether beginning, end, or
618 * somewhere in the middle. This releases the object.
619 * @param object to remove.
620 * @return true if object was removed, false if not found.
621 */
622 inline bool remove(T *object)
623 {return Queue::remove(object);};
624
625 /**
626 * Post a typed object into the queue by it's pointer. This can wait for
627 * a specified timeout if the queue is full, for example, for another
628 * thread to remove an object pointer. This retains the object.
629 * @param object to post.
630 * @param timeout to wait if queue is full in milliseconds.
631 * @return true if object posted, false if queue full and timeout expired.
632 */
633 inline bool post(T *object, timeout_t timeout = 0)
634 {return Queue::post(object);};
635
636 /**
637 * Get and remove first typed object posted to the queue. This can wait for
638 * a specified timeut of the queue is empty. The object is still retained
639 * and must be released or deleted by the receiving function.
640 * @param timeout to wait if empty in milliseconds.
641 * @return object from queue or NULL if empty and timed out.
642 */
643 inline T *fifo(timeout_t timeout = 0)
644 {return static_cast<T *>(Queue::fifo(timeout));};
645
646 /**
647 * Get and remove last typed object posted to the queue. This can wait for
648 * a specified timeout of the queue is empty. The object is still retained
649 * and must be released or deleted by the receiving function.
650 * @param timeout to wait if empty in milliseconds.
651 * @return object from queue or NULL if empty and timed out.
652 */
653 inline T *lifo(timeout_t timeout = 0)
654 {return static_cast<T *>(Queue::lifo(timeout));};
655
656 /**
657 * Examine past item in the queue. This is a typecast of the peek
658 * operation.
659 * @param offset in queue.
660 * @return item pointer if valid or NULL.
661 */
662 inline const T& at(unsigned offset = 0)
663 {return static_cast<const T&>(Queue::get(offset));};
664
665 /**
666 * Examine past item in the queue. This is a typecast of the peek
667 * operation.
668 * @param offset in queue.
669 * @return item pointer if valid or NULL.
670 */
671 inline T& operator[](unsigned offset)
672 {return static_cast<T&>(Queue::get(offset));};
673
674 inline T* operator()(unsigned offset = 0)
675 {return static_cast<T*>(Queue::get(offset));}
676};
677
678/**
679 * Convenience type for using thread-safe object stacks.
680 */
681typedef Stack stack_t;
682
683/**
684 * Convenience type for using thread-safe object fifo (queue).
685 */
686typedef Queue fifo_t;
687
688END_NAMESPACE
689
690#endif