blob: 28a4d0bf114da01a71f082126c3af8056ce1af0c [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 * Generic templates for C++. These are templates that do not depend
20 * on any ucommon classes. They can be used for generic C++ programming.
21 * @file ucommon/generics.h
22 */
23
24#ifndef _UCOMMON_GENERICS_H_
25#define _UCOMMON_GENERICS_H_
26
27#ifndef _UCOMMON_CPR_H_
28#include <ucommon/cpr.h>
29#endif
30
31#include <cstdlib>
32#include <string.h>
33
34#ifdef NEW_STDLIB
35#include <stdexcept>
36#endif
37
38#if defined(NEW_STDLIB) || defined(OLD_STDLIB)
39#define THROW(x) throw x
40#define THROWS(x) throw(x)
41#define THROWS_ANY throw()
42#else
43#define THROW(x) ::abort()
44#define THROWS(x)
45#define THROWS_ANY
46#endif
47
48NAMESPACE_UCOMMON
49
50/**
51 * Generic smart pointer class. This is the original Common C++ "Pointer"
52 * class with a few additions.
53 * @author David Sugar <dyfet@gnutelephony.org>
54 */
55template <typename T>
56class pointer
57{
58protected:
59 unsigned *counter;
60 T *object;
61
62public:
63 inline void release(void) {
64 if(counter && --(*counter)==0) {
65 delete counter;
66 delete object;
67 }
68 object = NULL;
69 counter = NULL;
70 }
71
72 inline void retain(void) {
73 if(counter)
74 ++*counter;
75 }
76
77 inline void set(T* ptr) {
78 if(object != ptr) {
79 release();
80 counter = new unsigned;
81 *counter = 1;
82 object = ptr;
83 }
84 }
85
86 inline void set(const pointer<T> &ref) {
87 if(object == ref.object)
88 return;
89
90 if(counter && --(*counter)==0) {
91 delete counter;
92 delete object;
93 }
94 object = ref.object;
95 counter = ref.counter;
96 if(counter)
97 ++(*counter);
98 }
99
100 inline pointer() {
101 counter = NULL;
102 object = NULL;
103 }
104
105 inline explicit pointer(T* ptr = NULL) : object(ptr) {
106 if(object) {
107 counter = new unsigned;
108 *counter = 1;
109 }
110 else
111 counter = NULL;
112 }
113
114 inline pointer(const pointer<T> &ref) {
115 object = ref.object;
116 counter = ref.counter;
117 if(counter)
118 ++(*counter);
119 }
120
121 inline pointer& operator=(const pointer<T> &ref) {
122 this->set(ref);
123 return *this;
124 }
125
126 inline pointer& operator=(T *ptr) {
127 this->set(ptr);
128 return *this;
129 }
130
131 inline ~pointer()
132 {release();}
133
134 inline T& operator*() const
135 {return *object;};
136
137 inline T* operator->() const
138 {return object;};
139
140 inline bool operator!() const
141 {return (counter == NULL);};
142
143 inline operator bool() const
144 {return counter != NULL;};
145};
146
147/**
148 * Generic smart array class. This is the original Common C++ "Pointer" class
149 * with a few additions for arrays.
150 * @author David Sugar <dyfet@gnutelephony.org>
151 */
152template <typename T>
153class array_pointer
154{
155protected:
156 unsigned *counter;
157 T *array;
158
159public:
160 inline void release(void) {
161 if(counter && --(*counter)==0) {
162 delete counter;
163 delete[] array;
164 }
165 array = NULL;
166 counter = NULL;
167 }
168
169 inline void retain(void) {
170 if(counter)
171 ++*counter;
172 }
173
174 inline void set(T* ptr) {
175 if(array != ptr) {
176 release();
177 counter = new unsigned;
178 *counter = 1;
179 array = ptr;
180 }
181 }
182
183 inline void set(const array_pointer<T> &ref) {
184 if(array == ref.array)
185 return;
186
187 if(counter && --(*counter)==0) {
188 delete counter;
189 delete[] array;
190 }
191 array = ref.array;
192 counter = ref.counter;
193 if(counter)
194 ++(*counter);
195 }
196
197 inline array_pointer() {
198 counter = NULL;
199 array = NULL;
200 }
201
202 inline explicit array_pointer(T* ptr = NULL) : array(ptr) {
203 if(array) {
204 counter = new unsigned;
205 *counter = 1;
206 }
207 else
208 counter = NULL;
209 }
210
211 inline array_pointer(const array_pointer<T> &ref) {
212 array = ref.array;
213 counter = ref.counter;
214 if(counter)
215 ++(*counter);
216 }
217
218 inline array_pointer& operator=(const array_pointer<T> &ref) {
219 this->set(ref);
220 return *this;
221 }
222
223 inline array_pointer& operator=(T *ptr) {
224 this->set(ptr);
225 return *this;
226 }
227
228 inline ~array_pointer()
229 {release();}
230
231 inline T* operator*() const
232 {return array;};
233
234 inline T& operator[](size_t offset) const
235 {return array[offset];};
236
237 inline T* operator()(size_t offset) const
238 {return &array[offset];};
239
240 inline bool operator!() const
241 {return (counter == NULL);};
242
243 inline operator bool() const
244 {return counter != NULL;};
245};
246
247/**
248 * Manage temporary object stored on the heap. This is used to create a
249 * object on the heap who's scope is controlled by the scope of a member
250 * function call. Sometimes we have data types and structures which cannot
251 * themselves appear as auto variables. We may also have a limited stack
252 * frame size in a thread context, and yet have a dynamic object that we
253 * only want to exist during the life of the method call. Using temporary
254 * allows any type to be created from the heap but have a lifespan of a
255 * method's stack frame.
256 * @author David Sugar <dyfet@gnutelephony.org>
257 */
258template <typename T>
259class temporary
260{
261protected:
262 T *object;
263public:
264 /**
265 * Construct a temporary object, create our stack frame reference.
266 */
267 inline temporary()
268 {object = NULL;};
269
270 /**
271 * Disable copy constructor.
272 */
273 temporary(const temporary<T>&)
274 {::abort();};
275
276 /**
277 * Construct an assigned pointer.
278 */
279 inline temporary(T *ptr)
280 {object = ptr;};
281
282 /**
283 * Assign a temporary object. This adds a pointer to an existing
284 * type to the current temporary pointer. If the temporary was
285 * already assigned, then it is deleted.
286 * @param temp object to assign.
287 */
288 inline T& operator=(T *temp) {
289 if(object)
290 delete object;
291 object = temp;
292 return *this;
293 }
294
295 /**
296 * Assign a temporary object. This adds a pointer to an existing
297 * type to the current temporary pointer. If the temporary was
298 * already assigned, then it is deleted.
299 * @param temp object to assign.
300 */
301 inline void set(T *temp) {
302 if(object)
303 delete object;
304 object = temp;
305 }
306
307 /**
308 * Access heap object through our temporary directly.
309 * @return reference to heap resident object.
310 */
311 inline T& operator*() const
312 {return *object;};
313
314 /**
315 * Access members of our heap object through our temporary.
316 * @return member reference of heap object.
317 */
318 inline T* operator->() const
319 {return object;};
320
321 inline operator bool() const
322 {return object != NULL;};
323
324 inline bool operator!() const
325 {return object == NULL;};
326
327 inline ~temporary() {
328 if(object)
329 delete object;
330 object = NULL;
331 }
332};
333
334/**
335 * Manage temporary array stored on the heap. This is used to create an
336 * array on the heap who's scope is controlled by the scope of a member
337 * function call. Sometimes we have data types and structures which cannot
338 * themselves appear as auto variables. We may also have a limited stack
339 * frame size in a thread context, and yet have a dynamic object that we
340 * only want to exist during the life of the method call. Using temporary
341 * allows any type to be created from the heap but have a lifespan of a
342 * method's stack frame.
343 * @author David Sugar <dyfet@gnutelephony.org>
344 */
345template <typename T>
346class temp_array
347{
348protected:
349 T *array;
350 size_t size;
351
352public:
353 /**
354 * Construct a temporary object, create our stack frame reference.
355 */
356 inline temp_array(size_t s)
357 {array = new T[s]; size = s;};
358
359 /**
360 * Construct a temporary object with a copy of some initial value.
361 * @param initial object value to use.
362 */
363 inline temp_array(const T& initial, size_t s) {
364 array = new T[s];
365 size = s;
366 for(size_t p = 0; p < s; ++p)
367 array[p] = initial;
368 }
369
370 inline void reset(size_t s)
371 {delete[] array; array = new T[s]; size = s;};
372
373 inline void reset(const T& initial, size_t s) {
374 if(array)
375 delete[] array;
376 array = new T[s];
377 size = s;
378 for(size_t p = 0; p < s; ++p)
379 array[p] = initial;
380 }
381
382 inline void set(const T& initial) {
383 for(size_t p = 0; p < size; ++p)
384 array[p] = initial;
385 }
386
387 /**
388 * Disable copy constructor.
389 */
390 temp_array(const temp_array<T>&)
391 {::abort();};
392
393 inline operator bool() const
394 {return array != NULL;};
395
396 inline bool operator!() const
397 {return array == NULL;};
398
399 inline ~temp_array() {
400 if(array)
401 delete[] array;
402 array = NULL;
403 size = 0;
404 }
405
406 inline T& operator[](size_t offset) const {
407 crit(offset < size, "array out of bound");
408 return array[offset];
409 }
410
411 inline T* operator()(size_t offset) const {
412 crit(offset < size, "array out of bound");
413 return &array[offset];
414 }
415};
416
417/**
418 * Save and restore global objects in function call stack frames.
419 * @author David Sugar <dyfet@gnutelephony.org>
420 */
421template<typename T>
422class save_restore
423{
424private:
425 T *original;
426 T temp;
427
428public:
429 /**
430 * Save object into local copy and keep reference to the original object.
431 * @param object to save.
432 */
433 inline save_restore(T& object)
434 {original = &object; temp = object;};
435
436 /**
437 * Restore original when stack frame is released.
438 */
439 inline ~save_restore()
440 {*original = temp;};
441};
442
443/**
444 * Convenience function to validate object assuming it is castable to bool.
445 * @param object we are testing.
446 * @return true if object valid.
447 */
448template<class T>
449inline bool is(T& object)
450 {return object.operator bool();}
451
452/**
453 * Convenience function to test pointer object. This solves issues where
454 * some compilers get confused between bool and pointer operators.
455 * @param object we are testing.
456 * @return true if object points to NULL.
457 */
458template<typename T>
459inline bool isnull(T& object)
460 {return (bool)(object.operator*() == NULL);}
461
462/**
463 * Convenience function to test pointer-pointer object. This solves issues
464 * where some compilers get confused between bool and pointer operators.
465 * @param object we are testing.
466 * @return true if object points to NULL.
467 */
468template<typename T>
469inline bool isnullp(T *object)
470 {return (bool)(object->operator*() == NULL);}
471
472/**
473 * Convenience function to duplicate object pointer to heap.
474 * @param object we are duping.
475 * @return heap pointer instance.
476 */
477template<typename T>
478inline T* dup(const T& object)
479 {return new T(object);}
480
481template<typename T>
482inline void dupfree(T object)
483 {delete object;}
484
485template<>
486inline char *dup<char>(const char& object)
487 {return strdup(&object);}
488
489template<>
490inline void dupfree<char*>(char* object)
491 {::free(object);}
492
493/**
494 * Convenience function to reset an existing object.
495 * @param object type to reset.
496 */
497template<typename T>
498inline void reset_unsafe(T& object)
499 {new((caddr_t)&object) T;}
500
501/**
502 * Convenience function to zero an object and restore type info.
503 * @param object to zero in memory.
504 */
505template<typename T>
506inline void zero_unsafe(T& object)
507 {memset((void *)&object, 0, sizeof(T)); new((caddr_t)&object) T;}
508
509/**
510 * Convenience function to copy class.
511 * @param target to copy into.
512 * @param source to copy from.
513 */
514template<typename T>
515inline void copy_unsafe(T* target, const T* source)
516 {memcpy((void *)target, (void *)source, sizeof(T));}
517
518/**
519 * Convenience function to store object pointer into object.
520 * @param target to copy into.
521 * @param source to copy from.
522 */
523template<typename T>
524inline void store_unsafe(T& target, const T* source)
525 {memcpy((void *)&target, (void *)source, sizeof(T));}
526
527/**
528 * Convenience function to swap objects.
529 * @param o1 to swap.
530 * @param o2 to swap.
531 */
532template<typename T>
533inline void swap(T& o1, T& o2)
534 {cpr_memswap(&o1, &o2, sizeof(T));}
535
536/**
537 * Convenience function to return max of two objects.
538 * @param o1 to check.
539 * @param o2 to check.
540 * @return max object.
541 */
542template<typename T>
543inline T& (max)(T& o1, T& o2)
544{
545 return o1 > o2 ? o1 : o2;
546}
547
548/**
549 * Convenience function to return min of two objects.
550 * @param o1 to check.
551 * @param o2 to check.
552 * @return min object.
553 */
554template<typename T>
555inline T& (min)(T& o1, T& o2)
556{
557 return o1 < o2 ? o1 : o2;
558}
559
560/**
561 * Convenience macro to range restrict values.
562 * @param value to check.
563 * @param low value.
564 * @param high value.
565 * @return adjusted value.
566 */
567template<typename T>
568inline T& (limit)(T& value, T& low, T& high)
569{
570 return (value < low) ? low : ((value > high) ? high : value);
571}
572
573END_NAMESPACE
574
575#endif