~ubuntu-branches/ubuntu/wily/ginkgocadx/wily-proposed

« back to all changes in this revision

Viewing changes to src/cadxcore/yasper/yasper.h

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Tille
  • Date: 2011-05-02 08:09:26 UTC
  • Revision ID: james.westby@ubuntu.com-20110502080926-bql5wep49c7hg91t
Tags: upstream-2.4.1.1
ImportĀ upstreamĀ versionĀ 2.4.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  
 
3
 *  $Id$
 
4
 *  Ginkgo CADx Project
 
5
 *
 
6
 *  Code based on yasper
 
7
 * ==========================
 
8
 *
 
9
 * yasper - A non-intrusive reference counted pointer.
 
10
 *          Version: 1.04
 
11
 *
 
12
 *  Many ideas borrowed from Yonat Sharon and
 
13
 *  Andrei Alexandrescu.
 
14
 *
 
15
 * (zlib license)
 
16
 * ----------------------------------------------------------------------------------
 
17
 * Copyright (C) 2005-2007 Alex Rubinsteyn
 
18
 *
 
19
 * This software is provided 'as-is', without any express or implied
 
20
 * warranty.  In no event will the authors be held liable for any damages
 
21
 * arising from the use of this software.
 
22
 *
 
23
 * Permission is granted to anyone to use this software for any purpose,
 
24
 * including commercial applications, and to alter it and redistribute it
 
25
 * freely, subject to the following restrictions:
 
26
 *
 
27
 * 1. The origin of this software must not be misrepresented; you must not
 
28
 *    claim that you wrote the original software. If you use this software
 
29
 *    in a product, an acknowledgment in the product documentation would be
 
30
 *    appreciated but is not required.
 
31
 * 2. Altered source versions must be plainly marked as such, and must not be
 
32
 *    misrepresented as being the original software.
 
33
 * 3. This notice may not be removed or altered from any source distribution.
 
34
 *
 
35
 * -----------------------------------------------------------------------------------
 
36
 *
 
37
 * Send all questions, comments and bug reports to:
 
38
 * Alex Rubinsteyn (alex.rubinsteyn {at-nospam} gmail {dot} com)
 
39
 */
 
40
 
 
41
#pragma once
 
42
#include <iostream>
 
43
#include <exception>
 
44
#include <string>
 
45
 
 
46
#define GLOC() (__FILE__ ":" TOSTRING(__LINE__))
 
47
#define STRINGIFY(x) #x
 
48
#define TOSTRING(x) STRINGIFY(x)
 
49
 
 
50
#if defined(_WINDOWS)
 
51
#define SUSPEND_WAKEUP()
 
52
#define RESUME_WAKEUP()
 
53
 
 
54
#else
 
55
 
 
56
#include <signal.h>
 
57
#include <pthread.h>
 
58
#include <errno.h>
 
59
 
 
60
#define SUSPEND_WAKEUP()\
 
61
siginterrupt(SIGUSR2, 0)
 
62
 
 
63
#define RESUME_WAKEUP()\
 
64
siginterrupt(SIGUSR2, 1)
 
65
#endif
 
66
 
 
67
#if defined(_WINDOWS)
 
68
#include <windows.h>
 
69
 
 
70
class GCriticalSection
 
71
{
 
72
public:
 
73
        GCriticalSection()
 
74
        {
 
75
                ::InitializeCriticalSection(&m_buffer);
 
76
 
 
77
        }
 
78
 
 
79
        ~GCriticalSection()
 
80
        {
 
81
                ::DeleteCriticalSection(&m_buffer);
 
82
 
 
83
        }
 
84
 
 
85
        inline void Enter()
 
86
        {
 
87
                ::EnterCriticalSection(&m_buffer);
 
88
 
 
89
        }
 
90
 
 
91
        inline void Leave()
 
92
        {
 
93
                ::LeaveCriticalSection(&m_buffer);
 
94
        }
 
95
 
 
96
    CRITICAL_SECTION m_buffer;
 
97
 
 
98
};
 
99
#else
 
100
 
 
101
class GCriticalSection
 
102
{
 
103
public:
 
104
        GCriticalSection()
 
105
        {
 
106
                int err = pthread_mutex_init(&m_mutex, NULL);
 
107
                m_isOk = err == 0;
 
108
                if ( !m_isOk )
 
109
                {
 
110
                        std::cerr << "pthread_mutex_init() error: " << err << std::endl;
 
111
                }
 
112
        }
 
113
 
 
114
        ~GCriticalSection()
 
115
        {
 
116
                if ( m_isOk )
 
117
                {
 
118
                        int err = pthread_mutex_destroy(&m_mutex);
 
119
                        if ( err != 0 )
 
120
                        {
 
121
                                std::cerr << "pthread_mutex_destroy() error: " << err << std::endl;
 
122
                        }
 
123
                }
 
124
                else {
 
125
                        std::cerr << "pthread_mutex_destroy() error: Mutex no creado correctamente" << std::endl;
 
126
                }
 
127
        }
 
128
 
 
129
        inline void Enter()
 
130
        {
 
131
                if (m_isOk) {
 
132
                        int err = pthread_mutex_lock(&m_mutex);
 
133
                        switch ( err )
 
134
                        {
 
135
                                case EDEADLK:
 
136
                                        std::cerr << "pthread_mutex_lock() error: deadlock prevenido" << std::endl;
 
137
                                        break;
 
138
 
 
139
                                case EINVAL:
 
140
                                        std::cerr << "pthread_mutex_lock() error: No inicializado" << std::endl;
 
141
                                        break;
 
142
 
 
143
                                case 0:
 
144
                                        break;
 
145
 
 
146
                                default:
 
147
                                        std::cerr << "pthread_mutex_lock() error: " << err << std::endl;
 
148
                                        break;
 
149
                        }
 
150
                }
 
151
                else {
 
152
                        std::cerr << "pthread_mutex_lock() error: Mutex no creado correctamente" << std::endl;
 
153
                }
 
154
        }
 
155
 
 
156
        inline void Leave()
 
157
        {
 
158
                if (m_isOk) {
 
159
                        int err = pthread_mutex_unlock(&m_mutex);
 
160
                        switch ( err )
 
161
                        {
 
162
                                case EPERM:
 
163
                                        std::cerr << "pthread_mutex_unlock() error: No adquirido por el invocador" << std::endl;
 
164
                                        break;
 
165
 
 
166
                                case EINVAL:
 
167
                                        std::cerr << "pthread_mutex_unlock() error: No inicializado" << std::endl;
 
168
                                        break;
 
169
 
 
170
                                case 0:
 
171
                                        break;
 
172
 
 
173
                                default:
 
174
                                        std::cerr << "pthread_mutex_unlock() error: " << err << std::endl;
 
175
                                        break;
 
176
                        }
 
177
                }
 
178
                else {
 
179
                        std::cerr << "pthread_mutex_unlock() error: Mutex no creado correctamente" << std::endl;
 
180
                }
 
181
        }
 
182
 
 
183
private:
 
184
    pthread_mutex_t m_mutex;
 
185
    bool m_isOk;
 
186
 
 
187
};
 
188
#endif
 
189
 
 
190
 
 
191
 
 
192
class GLocker;
 
193
 
 
194
//----------------------------------------------------------------------------------------------------
 
195
//region Interfaz de soporte de cerrojos
 
196
//----------------------------------------------------------------------------------------------------
 
197
class GLockable
 
198
{
 
199
        //----------------------------------------------------------------------------------------------------
 
200
        //region Constructor y destructor
 
201
public:
 
202
 
 
203
        inline GLockable();
 
204
 
 
205
        inline ~GLockable();
 
206
 
 
207
        //endregion
 
208
 
 
209
        //----------------------------------------------------------------------------------------------------
 
210
        //region Interfaz de exclusion mutua
 
211
public:
 
212
 
 
213
        inline void Lock(const std::string& loc );
 
214
 
 
215
        inline void UnLock(const std::string& loc );
 
216
 
 
217
        //enregion
 
218
 
 
219
        //----------------------------------------------------------------------------------------------------
 
220
        //region Interfaz de exclusion mutua desde automatico
 
221
private:
 
222
 
 
223
        inline void AutoLock(GLocker* pLocker, const std::string& loc = "");
 
224
 
 
225
        inline void AutoUnLock(GLocker* pLocker);
 
226
 
 
227
        //enregion
 
228
 
 
229
        //----------------------------------------------------------------------------------------------------
 
230
        //region Interfaz de subscripcion
 
231
private:
 
232
 
 
233
        GLocker* m_pLocker; // ILocker que ha bloqueado el cerrojo.
 
234
        //endregion
 
235
 
 
236
        //----------------------------------------------------------------------------------------------------
 
237
        //region Atributos
 
238
private:
 
239
 
 
240
        bool               m_IsLocked;
 
241
        std::string        m_LocBloqueo;
 
242
        GCriticalSection*  m_pCS;             // El cerrojo real.
 
243
        GCriticalSection*  m_pCSRegistro;     // Cerrojo para registrar el ocasionador del bloqueo.
 
244
        //endregion
 
245
 
 
246
        friend class GLocker;
 
247
};
 
248
//endregion
 
249
 
 
250
//----------------------------------------------------------------------------------------------------
 
251
//region Helper de bloqueo automatico
 
252
//----------------------------------------------------------------------------------------------------
 
253
class GLocker
 
254
{
 
255
        //----------------------------------------------------------------------------------------------------
 
256
        //region Construccion y destruccion
 
257
public:
 
258
 
 
259
        inline GLocker( GLockable& pLockable, const std::string& loc = "" )
 
260
        {
 
261
                m_pLockable = &pLockable;
 
262
                m_LocInstanciacion = loc;
 
263
                //GTRACE("GNC::GCS::ILockable()");
 
264
                m_pLockable->AutoLock(this, m_LocInstanciacion);
 
265
        }
 
266
 
 
267
        inline GLocker( GLockable* pLockable, const std::string& loc = "" )
 
268
        {
 
269
                m_pLockable = pLockable;
 
270
                m_LocInstanciacion = loc;
 
271
                //GTRACE("GNC::GCS::ILockable()");
 
272
                m_pLockable->AutoLock(this, loc);
 
273
        }
 
274
 
 
275
        inline ~GLocker()
 
276
        {
 
277
                m_pLockable->AutoUnLock(this);
 
278
                //GTRACE("GNC::GCS::~ILockable()");
 
279
 
 
280
        }
 
281
        //endregion
 
282
 
 
283
        //----------------------------------------------------------------------------------------------------
 
284
        //region Atributos
 
285
private:
 
286
 
 
287
        GLockable* m_pLockable;
 
288
        std::string m_LocInstanciacion;
 
289
        //endregion
 
290
 
 
291
        friend class GLockable;
 
292
};
 
293
//endregion
 
294
 
 
295
 
 
296
//----------------------------------------------------------------------------------------------------
 
297
//region Implementacion de GLockable
 
298
inline GLockable::GLockable()
 
299
{
 
300
        m_pLocker = NULL;
 
301
        m_IsLocked = false;
 
302
        m_pCS = new GCriticalSection();
 
303
}
 
304
 
 
305
inline GLockable::~GLockable()
 
306
{
 
307
        if (m_IsLocked) {
 
308
                if (m_pLocker != NULL) {
 
309
                        std::cerr << "Error al destruir GLockable: El cerrojo continua autobloqueado por " << m_pLocker << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
 
310
                }
 
311
                else if (m_LocBloqueo.size() != 0) {
 
312
                        std::cerr << "Error al destruir GLockable: El cerrojo continua bloqueado por una llamada en " << m_LocBloqueo.c_str() << std::endl;
 
313
                }
 
314
                else {
 
315
                        std::cerr << "Error al destruir GLockable: El cerrojo continua bloqueado por una llamada sin registrar" << std::endl;
 
316
                }
 
317
        }
 
318
        if (m_pCS != NULL) {
 
319
                delete m_pCS;
 
320
        }
 
321
        m_pCS = NULL;
 
322
}
 
323
 
 
324
inline void GLockable::Lock(const std::string& loc )
 
325
{
 
326
        SUSPEND_WAKEUP();
 
327
        //----------------------------------------------------------------------------------------------------
 
328
        // Entrada a la seccion Critica
 
329
        //----------------------------------------------------------------------------------------------------
 
330
        if (m_IsLocked) {
 
331
                //GTRACE("GNC::GCS::Lock() en " << loc.c_str() << " Esperando liberacion desde bloqueo previo en " << m_LocBloqueo.c_str());
 
332
                m_pCS->Enter();
 
333
                m_LocBloqueo = loc;
 
334
                m_IsLocked = true;
 
335
                //GTRACE("GNC::GCS::Lock() en " << loc.c_str());
 
336
        }
 
337
        else {
 
338
                m_pCS->Enter();
 
339
                m_LocBloqueo = loc;
 
340
                m_IsLocked = true;
 
341
                //GTRACE("GNC::GCS::Lock() en " << loc.c_str());
 
342
        }
 
343
        RESUME_WAKEUP();
 
344
        //----------------------------------------------------------------------------------------------------
 
345
        //----------------------------------------------------------------------------------------------------
 
346
 
 
347
}
 
348
 
 
349
inline void GLockable::UnLock(const std::string& loc )
 
350
{
 
351
        //----------------------------------------------------------------------------------------------------
 
352
        // Salida de la seccion Critica
 
353
        //----------------------------------------------------------------------------------------------------
 
354
        if (!m_IsLocked) {
 
355
                std::cerr << "Error: El cerrojo no estaba bloqueado. (Tratado de liberar en " << loc.c_str() << ")" ;
 
356
        }
 
357
        else if (m_pLocker != NULL) {
 
358
                std::cerr << "Error: El cerrojo estaba auto bloqueado previamente por " << m_pLocker << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
 
359
 
 
360
        }
 
361
        else {
 
362
                //GTRACE("GNC::GCS::UnLock() en " << loc.c_str());
 
363
                //GTRACE("      >> Liberado bloqueo desde " << m_LocBloqueo.c_str());
 
364
                m_LocBloqueo = "";
 
365
                m_IsLocked = false;
 
366
                m_pCS->Leave();
 
367
        }
 
368
        //----------------------------------------------------------------------------------------------------
 
369
        //----------------------------------------------------------------------------------------------------
 
370
 
 
371
}
 
372
 
 
373
inline void GLockable::AutoLock(GLocker* pLocker, const std::string& loc)
 
374
{
 
375
        //----------------------------------------------------------------------------------------------------
 
376
        // Entrada a la seccion Critica
 
377
        //----------------------------------------------------------------------------------------------------
 
378
        SUSPEND_WAKEUP();
 
379
        m_pCS->Enter();
 
380
        m_IsLocked = true;
 
381
        m_pLocker = pLocker;
 
382
        m_LocBloqueo = loc;
 
383
#if defined(_GINKGO_TRACE)
 
384
        if (pLocker != NULL) {
 
385
                //GTRACE("GNC::GCS::Lock() automatico por " << pLocker << " instanciado en " << pLocker->m_LocInstanciacion.c_str());
 
386
        }
 
387
        else {
 
388
                //GTRACE("GNC::GCS::Lock() automatico por NULL (ĀæError?)");
 
389
        }
 
390
#endif
 
391
        RESUME_WAKEUP();
 
392
        //----------------------------------------------------------------------------------------------------
 
393
        //----------------------------------------------------------------------------------------------------
 
394
 
 
395
}
 
396
 
 
397
inline void GLockable::AutoUnLock(GLocker* pLocker)
 
398
{
 
399
        //----------------------------------------------------------------------------------------------------
 
400
        // Salida de la seccion Critica
 
401
        //----------------------------------------------------------------------------------------------------
 
402
        if (!m_IsLocked) {
 
403
                std::cerr << "Error: El cerrojo no estaba bloqueado. (Tratado de liberar automaticamente por " << pLocker;
 
404
                if (pLocker != NULL) {
 
405
                        std::cerr << " instanciado en " << pLocker->m_LocInstanciacion.c_str() << ")" << std::endl;
 
406
                }
 
407
                else {
 
408
                        std::cerr << ")" << std::endl;
 
409
                }
 
410
        }
 
411
        else if (m_pLocker != pLocker) {
 
412
                std::cerr << "Error: Se ha liberado un bloqueo desde un Locker automatico distinto del que lo inicio: " << std::endl;
 
413
                std::cerr << "\tIniciado por " << m_pLocker;
 
414
                if (m_pLocker != NULL) {
 
415
                        std::cerr << " instanciado en " << m_pLocker->m_LocInstanciacion.c_str() << std::endl;
 
416
                }
 
417
                else {
 
418
                        std::cerr << std::endl;
 
419
                }
 
420
                std::cerr << "\tTratado de liberar  por " << pLocker;
 
421
                if (pLocker != NULL) {
 
422
                        std::cerr << " instanciado en " << pLocker->m_LocInstanciacion.c_str() << std::endl;
 
423
                }
 
424
                else {
 
425
                        std::cerr << std::endl;
 
426
                }
 
427
        }
 
428
        else {
 
429
#if defined (_GINKGO_TRACE)
 
430
                if (pLocker != NULL) {
 
431
                        //GTRACE("GNC::GCS::UnLock() automatico por " << pLocker << " instanciado en " << pLocker->m_LocInstanciacion.c_str());
 
432
                }
 
433
                else {
 
434
                        //GTRACE("GNC::GCS::UnLock() automatico por " << pLocker);
 
435
                }
 
436
#endif
 
437
                m_LocBloqueo = "";
 
438
                m_IsLocked = false;
 
439
                m_pCS->Leave();
 
440
        }
 
441
        //----------------------------------------------------------------------------------------------------
 
442
        //----------------------------------------------------------------------------------------------------
 
443
 
 
444
}
 
445
 
 
446
//endregion
 
447
 
 
448
struct GnkNullPointerException : public std::exception
 
449
{
 
450
    GnkNullPointerException() throw() {}
 
451
    ~GnkNullPointerException() throw() {}
 
452
 
 
453
    const char* what() const throw()
 
454
    {
 
455
        return "[Yasper Exception] Attempted to dereference null pointer";
 
456
    }
 
457
};
 
458
 
 
459
class GnkCounter : public GLockable
 
460
{
 
461
public:
 
462
        GnkCounter(unsigned c = 1) : count(c) {}
 
463
 
 
464
        unsigned count;
 
465
};
 
466
 
 
467
template <typename X>
 
468
class GnkPtr : public GLockable
 
469
{
 
470
 
 
471
public:
 
472
    typedef X element_type;
 
473
 
 
474
        /*
 
475
         GnkPtr needs to be its own friend so GnkPtr< X > and GnkPtr< Y > can access
 
476
         each other's private data members
 
477
         */
 
478
        template <class Y> friend class GnkPtr;
 
479
        /*
 
480
         default constructor
 
481
         - don't create GnkCounter
 
482
         */
 
483
        GnkPtr() : rawPtr(0), counter(0) { }
 
484
 
 
485
        /*
 
486
         Construct from a raw pointer
 
487
         */
 
488
        GnkPtr(X* raw, GnkCounter* c = 0) : rawPtr(0), counter(0)
 
489
        {
 
490
                Lock(GLOC());
 
491
                if (raw)
 
492
                {
 
493
                        if (c) {
 
494
                                c->Lock(GLOC());
 
495
                                acquire(c);
 
496
                                rawPtr = raw;
 
497
                                c->UnLock(GLOC());
 
498
                        }
 
499
                        else {
 
500
                                counter = new GnkCounter;
 
501
                                rawPtr = raw;
 
502
                        }
 
503
                }
 
504
                UnLock(GLOC());
 
505
        }
 
506
 
 
507
        template <typename Y>
 
508
        explicit GnkPtr(Y* raw, GnkCounter* c = 0) : rawPtr(0), counter(0)
 
509
        {
 
510
                Lock(GLOC());
 
511
                if (raw)
 
512
                {
 
513
                        if (c) {
 
514
                                c->Lock(GLOC());
 
515
                                acquire(c);
 
516
                                rawPtr = static_cast<X*>( raw );
 
517
                                c->UnLock(GLOC());
 
518
                        }
 
519
                        else {
 
520
                                rawPtr = static_cast<X*>( raw );
 
521
                                counter = new GnkCounter;
 
522
                        }
 
523
                }
 
524
                UnLock(GLOC());
 
525
        }
 
526
 
 
527
 
 
528
        /*
 
529
         Copy constructor
 
530
         */
 
531
        GnkPtr(const GnkPtr< X >& otherPtr)
 
532
        {
 
533
                Lock(GLOC());
 
534
                ( (GnkPtr<X>*) &otherPtr)->Lock(GLOC());
 
535
 
 
536
                if (otherPtr.counter) {
 
537
                        otherPtr.counter->Lock(GLOC());
 
538
 
 
539
                        acquire( otherPtr.counter );
 
540
                        rawPtr = otherPtr.rawPtr;
 
541
                        otherPtr.counter->UnLock(GLOC());
 
542
                }
 
543
                else {
 
544
                        counter = NULL;
 
545
                        rawPtr = NULL;
 
546
                }
 
547
 
 
548
                ( (GnkPtr<X>*) &otherPtr)->UnLock(GLOC());
 
549
                UnLock(GLOC());
 
550
        }
 
551
 
 
552
        template <typename Y>
 
553
        explicit GnkPtr(const GnkPtr< Y >& otherPtr) : rawPtr(0), counter(0)
 
554
        {
 
555
                Lock(GLOC());
 
556
                ( (GnkPtr<Y>*) &otherPtr)->Lock(GLOC());
 
557
 
 
558
                if (otherPtr.counter) {
 
559
                        otherPtr.counter->Lock(GLOC());
 
560
 
 
561
                        acquire(otherPtr.counter);
 
562
                        rawPtr = static_cast<X*>( otherPtr.rawPtr );
 
563
 
 
564
                        otherPtr.counter->UnLock(GLOC());
 
565
                }
 
566
 
 
567
                ( (GnkPtr<Y>*) &otherPtr)->UnLock(GLOC());
 
568
                UnLock(GLOC());
 
569
        }
 
570
 
 
571
 
 
572
        /*
 
573
         Destructor
 
574
         */
 
575
        ~GnkPtr()
 
576
        {
 
577
                Lock(GLOC());
 
578
                release();
 
579
                UnLock(GLOC());
 
580
        }
 
581
 
 
582
        /*
 
583
         Assignment to another GnkPtr
 
584
         */
 
585
 
 
586
        GnkPtr& operator=(const GnkPtr< X >& otherPtr)
 
587
        {
 
588
                Lock(GLOC());
 
589
 
 
590
                ( (GnkPtr<X>*) &otherPtr)->Lock(GLOC());
 
591
 
 
592
                if (this != &otherPtr)
 
593
                {
 
594
                        release();
 
595
 
 
596
                        if (otherPtr.counter) {
 
597
                                otherPtr.counter->Lock(GLOC());
 
598
 
 
599
                                acquire(otherPtr.counter);
 
600
                                rawPtr = static_cast<X*> (otherPtr.rawPtr);
 
601
 
 
602
                                otherPtr.counter->UnLock(GLOC());
 
603
                        }
 
604
                        else {
 
605
                                rawPtr = NULL;
 
606
                                counter = NULL;
 
607
                        }
 
608
 
 
609
 
 
610
                }
 
611
 
 
612
                ( (GnkPtr<X>*) &otherPtr)->UnLock(GLOC());
 
613
 
 
614
                UnLock(GLOC());
 
615
 
 
616
                return *this;
 
617
        }
 
618
 
 
619
        template <typename Y>
 
620
        GnkPtr& operator=(const GnkPtr< Y >& otherPtr)
 
621
        {
 
622
                Lock(GLOC());
 
623
                ( (GnkPtr<Y>*) &otherPtr)->Lock(GLOC());
 
624
 
 
625
                if ( this != (GnkPtr< X >*) &otherPtr )
 
626
                {
 
627
                        release();
 
628
 
 
629
                        if (otherPtr.counter) {
 
630
                                otherPtr.counter->Lock(GLOC());
 
631
 
 
632
                                acquire(otherPtr.counter);
 
633
                                rawPtr = static_cast<X*> (otherPtr.rawPtr);
 
634
 
 
635
                                otherPtr.counter->UnLock(GLOC());
 
636
                        }
 
637
                }
 
638
 
 
639
                ( (GnkPtr<Y>*) &otherPtr)->UnLock(GLOC());
 
640
                UnLock(GLOC());
 
641
                return *this;
 
642
        }
 
643
 
 
644
        /*
 
645
         Assignment to raw pointers is really dangerous business.
 
646
         If the raw pointer is also being used elsewhere,
 
647
         we might prematurely delete it, causing much pain.
 
648
         Use sparingly/with caution.
 
649
         */
 
650
 
 
651
        GnkPtr& operator=(X* raw)
 
652
        {
 
653
                Lock(GLOC());
 
654
                if (raw)
 
655
                {
 
656
                        release();
 
657
 
 
658
                        GnkCounter* c = new GnkCounter;
 
659
                        c->Lock(GLOC());
 
660
 
 
661
                        counter = c;
 
662
                        rawPtr = raw;
 
663
 
 
664
                        c->UnLock(GLOC());
 
665
 
 
666
                }
 
667
                UnLock(GLOC());
 
668
                return *this;
 
669
        }
 
670
 
 
671
        template <typename Y>
 
672
        GnkPtr& operator=(Y* raw)
 
673
        {
 
674
                Lock(GLOC());
 
675
                if (raw)
 
676
                {
 
677
                        release();
 
678
 
 
679
                        GnkCounter* c = new GnkCounter();
 
680
 
 
681
                        c->Lock(GLOC());
 
682
 
 
683
                        counter = c;
 
684
                        rawPtr = static_cast<X*>(raw);
 
685
 
 
686
                        c->UnLock(GLOC());
 
687
 
 
688
                }
 
689
                UnLock(GLOC());
 
690
                return *this;
 
691
        }
 
692
 
 
693
        /*
 
694
         assignment to long to allow GnkPtr< X > = NULL,
 
695
         also allows raw pointer assignment by conversion.
 
696
         Raw pointer assignment is really dangerous!
 
697
         If the raw pointer is being used elsewhere,
 
698
         it will get deleted prematurely.
 
699
         */
 
700
        GnkPtr& operator=(long num)
 
701
        {
 
702
                Lock(GLOC());
 
703
                if (num == 0)  //pointer set to null
 
704
                {
 
705
                        release();
 
706
                }
 
707
 
 
708
                else //assign raw pointer by conversion
 
709
                {
 
710
                        release();
 
711
                        GnkCounter* c = new GnkCounter();
 
712
 
 
713
                        c->Lock(GLOC());
 
714
 
 
715
                        counter = c;
 
716
                        rawPtr = reinterpret_cast<X*>(num);
 
717
 
 
718
                        c->UnLock(GLOC());
 
719
 
 
720
                }
 
721
                UnLock(GLOC());
 
722
 
 
723
                return *this;
 
724
        }
 
725
 
 
726
        /*
 
727
         Member Access
 
728
         */
 
729
        X* operator->() const
 
730
        {
 
731
                return GetRawPointer();
 
732
        }
 
733
 
 
734
 
 
735
        /*
 
736
         Dereference the pointer
 
737
         */
 
738
        X& operator* () const
 
739
        {
 
740
                return *GetRawPointer();
 
741
        }
 
742
 
 
743
 
 
744
        /*
 
745
         Conversion/casting operators
 
746
         */
 
747
 
 
748
 
 
749
        operator bool() const
 
750
        {
 
751
                return IsValid();
 
752
        }
 
753
 
 
754
 
 
755
        /*
 
756
         implicit casts to base types of the
 
757
         the pointer we're storing
 
758
         */
 
759
 
 
760
        template <typename Y>
 
761
        operator Y*() const
 
762
        {
 
763
                Y* r = NULL;
 
764
 
 
765
                ( (GnkPtr<Y>*) this)->Lock(GLOC());
 
766
                r = static_cast<Y*>(rawPtr);
 
767
                ( (GnkPtr<Y>*) this)->UnLock(GLOC());
 
768
 
 
769
                return r;
 
770
        }
 
771
 
 
772
        template <typename Y>
 
773
        operator const Y*() const
 
774
        {
 
775
                const Y* r = NULL;
 
776
                ( (GnkPtr<Y>*) this)->Lock(GLOC());
 
777
                r = static_cast<const Y*>(rawPtr);
 
778
                ( (GnkPtr<Y>*) this)->UnLock(GLOC());
 
779
                return r;
 
780
        }
 
781
 
 
782
        template <typename Y>
 
783
        operator GnkPtr<Y>()
 
784
        {
 
785
                //new GnkPtr must also take our counter or else the reference counts
 
786
                //will go out of sync
 
787
                return GnkPtr<Y>(rawPtr, counter);
 
788
        }
 
789
 
 
790
 
 
791
        /*
 
792
         Provide access to the raw pointer
 
793
         */
 
794
 
 
795
        X* GetRawPointer() const
 
796
        {
 
797
                X* r = NULL;
 
798
 
 
799
                r = rawPtr;
 
800
 
 
801
                if (r == 0) {
 
802
                        throw new GnkNullPointerException;
 
803
                }
 
804
 
 
805
                return r;
 
806
        }
 
807
 
 
808
 
 
809
        /*
 
810
         Is there only one reference on the counter?
 
811
         */
 
812
        bool IsUnique() const
 
813
        {
 
814
                bool unique = false;
 
815
 
 
816
                Lock(GLOC());
 
817
                if (counter) {
 
818
                        counter->Lock(GLOC());
 
819
                        unique = (counter->count == 1);
 
820
                        counter->UnLock(GLOC());
 
821
                }
 
822
                else {
 
823
                        unique = true;
 
824
                }
 
825
                UnLock(GLOC());
 
826
 
 
827
                return unique;
 
828
        }
 
829
 
 
830
        bool IsValid() const
 
831
        {
 
832
                bool valid = false;
 
833
 
 
834
                if (counter) {
 
835
                        counter->Lock(GLOC());
 
836
                        valid = (rawPtr != NULL);
 
837
                        counter->UnLock(GLOC());
 
838
                }
 
839
 
 
840
                return valid;
 
841
        }
 
842
 
 
843
        unsigned GetCount() const
 
844
        {
 
845
                int count = 0;
 
846
                Lock(GLOC());
 
847
 
 
848
                if (counter) {
 
849
                        counter->Lock(GLOC());
 
850
                        count = counter->count;
 
851
                        counter->UnLock(GLOC());
 
852
                }
 
853
                UnLock(GLOC());
 
854
                return 0;
 
855
        }
 
856
 
 
857
private:
 
858
        X* rawPtr;
 
859
 
 
860
        GnkCounter* counter;
 
861
 
 
862
        // increment the count
 
863
        void acquire(GnkCounter* c)
 
864
        {
 
865
                counter = c;
 
866
                (c->count)++;
 
867
        }
 
868
 
 
869
        // decrement the count, delete if it is 0
 
870
        void release()
 
871
        {
 
872
                if (counter)
 
873
                {
 
874
                        GnkCounter* c = counter;
 
875
 
 
876
                        c->Lock(GLOC());
 
877
 
 
878
                        X* r = rawPtr;
 
879
 
 
880
                        (c->count)--;
 
881
 
 
882
                        if (c->count == 0)
 
883
                        {
 
884
                                counter = NULL;
 
885
                                rawPtr = NULL;
 
886
 
 
887
                                c->UnLock(GLOC());
 
888
 
 
889
                                delete c;
 
890
                                delete r;
 
891
                        }
 
892
                        else {
 
893
                                c->UnLock(GLOC());
 
894
                        }
 
895
 
 
896
                }
 
897
 
 
898
        }
 
899
};
 
900
 
 
901
 
 
902
template <typename X, typename Y>
 
903
bool operator==(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
 
904
{
 
905
        return lGnkPtr.GetRawPointer() == rGnkPtr.GetRawPointer();
 
906
}
 
907
 
 
908
template <typename X, typename Y>
 
909
bool operator==(const GnkPtr< X >& lGnkPtr, Y* raw)
 
910
{
 
911
        return lGnkPtr.GetRawPointer() == raw ;
 
912
}
 
913
 
 
914
template <typename X>
 
915
bool operator==(const GnkPtr< X >& lGnkPtr, long num)
 
916
{
 
917
        if (num == 0 && !lGnkPtr.IsValid())  //both pointer and address are null
 
918
        {
 
919
                return true;
 
920
        }
 
921
 
 
922
        else //convert num to a pointer, compare addresses
 
923
        {
 
924
                return lGnkPtr == reinterpret_cast<X*>(num);
 
925
        }
 
926
 
 
927
}
 
928
 
 
929
template <typename X, typename Y>
 
930
bool operator!=(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
 
931
{
 
932
        return ( !operator==(lGnkPtr, rGnkPtr) );
 
933
}
 
934
 
 
935
template <typename X, typename Y>
 
936
bool operator!=(const GnkPtr< X >& lGnkPtr, Y* raw)
 
937
{
 
938
        return ( !operator==(lGnkPtr, raw) );
 
939
}
 
940
 
 
941
template <typename X>
 
942
bool operator!=(const GnkPtr< X >& lGnkPtr, long num)
 
943
{
 
944
        return (!operator==(lGnkPtr, num) );
 
945
}
 
946
 
 
947
template <typename X, typename Y>
 
948
bool operator&&(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
 
949
{
 
950
        return lGnkPtr.IsValid() &&  rGnkPtr.IsValid();
 
951
}
 
952
 
 
953
template <typename X>
 
954
bool operator&&(const GnkPtr< X >& lGnkPtr, bool rval)
 
955
{
 
956
        return lGnkPtr.IsValid() && rval;
 
957
}
 
958
 
 
959
template <typename X>
 
960
bool operator&&(bool lval, const GnkPtr< X >& rGnkPtr)
 
961
{
 
962
        return lval &&  rGnkPtr.IsValid();
 
963
}
 
964
 
 
965
template <typename X, typename Y>
 
966
bool operator||(const GnkPtr< X >& lGnkPtr, const GnkPtr< Y >& rGnkPtr)
 
967
{
 
968
        return lGnkPtr.IsValid() || rGnkPtr.IsValid();
 
969
}
 
970
 
 
971
template <typename X>
 
972
bool operator||(const GnkPtr< X >& lGnkPtr, bool rval)
 
973
{
 
974
        return lGnkPtr.IsValid() || rval;
 
975
}
 
976
 
 
977
template <typename X>
 
978
bool operator||(bool lval, const GnkPtr< X >& rGnkPtr)
 
979
{
 
980
        return lval || rGnkPtr.IsValid();
 
981
}
 
982
 
 
983
template <typename X>
 
984
bool operator!(const GnkPtr< X >& p)
 
985
{
 
986
        return (!p.IsValid());
 
987
}
 
988
 
 
989
 
 
990
/* less than comparisons for storage in containers */
 
991
template <typename X, typename Y>
 
992
bool operator< (const GnkPtr< X >& lGnkPtr, const GnkPtr < Y >& rGnkPtr)
 
993
{
 
994
        return lGnkPtr.GetRawPointer() < rGnkPtr.GetRawPointer();
 
995
}
 
996
 
 
997
template <typename X, typename Y>
 
998
bool operator< (const GnkPtr< X >& lGnkPtr, Y* raw)
 
999
{
 
1000
        return lGnkPtr.GetRawPointer() < raw;
 
1001
}
 
1002
 
 
1003
template <typename X, typename Y>
 
1004
bool operator< (X* raw, const GnkPtr< Y >& rGnkPtr)
 
1005
{
 
1006
        return raw < rGnkPtr.GetRawPointer();
 
1007
}
 
1008
 
 
1009