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 _FSSH_AUTO_LOCKER_H
6#define _FSSH_AUTO_LOCKER_H
7
8
9#include <fssh_types.h>
10
11
12namespace FSShell {
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// AutoLockerReadLocking
30template<typename Lockable>
31class AutoLockerReadLocking {
32public:
33	inline bool Lock(Lockable *lockable)
34	{
35		return lockable->ReadLock();
36	}
37
38	inline void Unlock(Lockable *lockable)
39	{
40		lockable->ReadUnlock();
41	}
42};
43
44// AutoLockerWriteLocking
45template<typename Lockable>
46class AutoLockerWriteLocking {
47public:
48	inline bool Lock(Lockable *lockable)
49	{
50		return lockable->WriteLock();
51	}
52
53	inline void Unlock(Lockable *lockable)
54	{
55		lockable->WriteUnlock();
56	}
57};
58
59// AutoLocker
60template<typename Lockable,
61		 typename Locking = AutoLockerStandardLocking<Lockable> >
62class AutoLocker {
63private:
64	typedef AutoLocker<Lockable, Locking>	ThisClass;
65public:
66	inline AutoLocker()
67		: fLockable(NULL),
68		  fLocked(false)
69	{
70	}
71
72	inline AutoLocker(Lockable *lockable, bool alreadyLocked = false,
73		bool lockIfNotLocked = true)
74		: fLockable(lockable),
75		  fLocked(fLockable && alreadyLocked)
76	{
77		if (!alreadyLocked && lockIfNotLocked)
78			Lock();
79	}
80
81	inline AutoLocker(Lockable &lockable, bool alreadyLocked = false,
82		bool lockIfNotLocked = true)
83		: fLockable(&lockable),
84		  fLocked(fLockable && alreadyLocked)
85	{
86		if (!alreadyLocked && lockIfNotLocked)
87			Lock();
88	}
89
90	inline ~AutoLocker()
91	{
92		Unlock();
93	}
94
95	inline void SetTo(Lockable *lockable, bool alreadyLocked,
96		bool lockIfNotLocked = true)
97	{
98		Unlock();
99		fLockable = lockable;
100		fLocked = alreadyLocked;
101		if (!alreadyLocked && lockIfNotLocked)
102			Lock();
103	}
104
105	inline void SetTo(Lockable &lockable, bool alreadyLocked,
106		bool lockIfNotLocked = true)
107	{
108		SetTo(&lockable, alreadyLocked, lockIfNotLocked);
109	}
110
111	inline void Unset()
112	{
113		Unlock();
114		Detach();
115	}
116
117	inline bool Lock()
118	{
119		if (fLockable && !fLocked)
120			fLocked = fLocking.Lock(fLockable);
121		return fLocked;
122	}
123
124	inline void Unlock()
125	{
126		if (fLockable && fLocked) {
127			fLocking.Unlock(fLockable);
128			fLocked = false;
129		}
130	}
131
132	inline void Detach()
133	{
134		fLockable = NULL;
135		fLocked = false;
136	}
137
138	inline AutoLocker<Lockable, Locking> &operator=(Lockable *lockable)
139	{
140		SetTo(lockable);
141		return *this;
142	}
143
144	inline AutoLocker<Lockable, Locking> &operator=(Lockable &lockable)
145	{
146		SetTo(&lockable);
147		return *this;
148	}
149
150	inline bool IsLocked() const	{ return fLocked; }
151
152	inline operator bool() const	{ return fLocked; }
153
154private:
155	Lockable	*fLockable;
156	bool		fLocked;
157	Locking		fLocking;
158};
159
160
161}	// namespace FSShell
162
163using FSShell::AutoLocker;
164
165#endif	// _FSSH_AUTO_LOCKER_H
166