1/*
2 * Copyright 2005-2007, Ingo Weinhold, bonefish@users.sf.net.
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5#ifndef _AUTO_LOCKER_H
6#define _AUTO_LOCKER_H
7
8
9#include <stddef.h>
10
11
12namespace BPrivate {
13
14// AutoLockerStandardLocking
15template<typename Lockable>
16class AutoLockerStandardLocking {
17public:
18	inline bool Lock(Lockable* lockable)
19	{
20		return lockable->Lock();
21	}
22
23	inline void Unlock(Lockable* lockable)
24	{
25		lockable->Unlock();
26	}
27};
28
29// AutoLockerHandlerLocking
30template<typename Lockable>
31class AutoLockerHandlerLocking {
32public:
33	inline bool Lock(Lockable* lockable)
34	{
35		return lockable->LockLooper();
36	}
37
38	inline void Unlock(Lockable* lockable)
39	{
40		lockable->UnlockLooper();
41	}
42};
43
44// AutoLockerReadLocking
45template<typename Lockable>
46class AutoLockerReadLocking {
47public:
48	inline bool Lock(Lockable* lockable)
49	{
50		return lockable->ReadLock();
51	}
52
53	inline void Unlock(Lockable* lockable)
54	{
55		lockable->ReadUnlock();
56	}
57};
58
59// AutoLockerWriteLocking
60template<typename Lockable>
61class AutoLockerWriteLocking {
62public:
63	inline bool Lock(Lockable* lockable)
64	{
65		return lockable->WriteLock();
66	}
67
68	inline void Unlock(Lockable* lockable)
69	{
70		lockable->WriteUnlock();
71	}
72};
73
74// AutoLocker
75template<typename Lockable,
76		 typename Locking = AutoLockerStandardLocking<Lockable> >
77class AutoLocker {
78private:
79	typedef AutoLocker<Lockable, Locking>	ThisClass;
80public:
81	inline AutoLocker()
82		:
83		fLockable(NULL),
84		fLocked(false)
85	{
86	}
87
88	inline AutoLocker(const Locking& locking)
89		:
90		fLockable(NULL),
91		fLocking(locking),
92		fLocked(false)
93	{
94	}
95
96	inline AutoLocker(Lockable* lockable, bool alreadyLocked = false,
97		bool lockIfNotLocked = true)
98		:
99		fLockable(lockable),
100		fLocked(fLockable && alreadyLocked)
101	{
102		if (!alreadyLocked && lockIfNotLocked)
103			Lock();
104	}
105
106	inline AutoLocker(Lockable& lockable, bool alreadyLocked = false,
107		bool lockIfNotLocked = true)
108		:
109		fLockable(&lockable),
110		fLocked(fLockable && alreadyLocked)
111	{
112		if (!alreadyLocked && lockIfNotLocked)
113			Lock();
114	}
115
116	inline ~AutoLocker()
117	{
118		Unlock();
119	}
120
121	inline void SetTo(Lockable* lockable, bool alreadyLocked,
122		bool lockIfNotLocked = true)
123	{
124		Unlock();
125		fLockable = lockable;
126		fLocked = (lockable && alreadyLocked);
127		if (!alreadyLocked && lockIfNotLocked)
128			Lock();
129	}
130
131	inline void SetTo(Lockable& lockable, bool alreadyLocked,
132		bool lockIfNotLocked = true)
133	{
134		SetTo(&lockable, alreadyLocked, lockIfNotLocked);
135	}
136
137	inline void Unset()
138	{
139		Unlock();
140		Detach();
141	}
142
143	inline bool Lock()
144	{
145		if (fLockable && !fLocked)
146			fLocked = fLocking.Lock(fLockable);
147		return fLocked;
148	}
149
150	inline void Unlock()
151	{
152		if (fLockable && fLocked) {
153			fLocking.Unlock(fLockable);
154			fLocked = false;
155		}
156	}
157
158	inline Lockable* Get()
159	{
160		return fLockable;
161	}
162
163	inline Lockable* Detach()
164	{
165		Lockable* res = fLockable;
166		fLockable = NULL;
167		fLocked = false;
168		return res;
169	}
170
171	inline AutoLocker<Lockable, Locking>& operator=(Lockable* lockable)
172	{
173		SetTo(lockable);
174		return *this;
175	}
176
177	inline AutoLocker<Lockable, Locking>& operator=(Lockable& lockable)
178	{
179		SetTo(&lockable);
180		return *this;
181	}
182
183	inline bool IsLocked() const	{ return fLocked; }
184
185	inline operator bool() const	{ return fLocked; }
186
187protected:
188	Lockable*	fLockable;
189	Locking		fLocking;
190	bool		fLocked;
191};
192
193
194}	// namespace BPrivate
195
196using ::BPrivate::AutoLocker;
197using ::BPrivate::AutoLockerHandlerLocking;
198using ::BPrivate::AutoLockerReadLocking;
199using ::BPrivate::AutoLockerWriteLocking;
200
201#endif	// _AUTO_LOCKER_H
202