Zero  0.1.0
guard.h
Go to the documentation of this file.
1 /* -*- mode:C++; c-basic-offset:4 -*-
2  Shore-kits -- Benchmark implementations for Shore-MT
3 
4  Copyright (c) 2007-2009
5  Data Intensive Applications and Systems Labaratory (DIAS)
6  Ecole Polytechnique Federale de Lausanne
7 
8  All Rights Reserved.
9 
10  Permission to use, copy, modify and distribute this software and
11  its documentation is hereby granted, provided that both the
12  copyright notice and this permission notice appear in all copies of
13  the software, derivative works or modified versions, and any
14  portions thereof, and that both notices appear in supporting
15  documentation.
16 
17  This code is distributed in the hope that it will be useful, but
18  WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
20  DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
21  RESULTING FROM THE USE OF THIS SOFTWARE.
22 */
23 
24 #ifndef __GUARD_H
25 #define __GUARD_H
26 
27 #include <cstdio>
28 #include <cassert>
29 #include <cstddef>
30 #include <unistd.h>
31 #include "trace.h"
32 #include <type_traits> // alignment_of
33 
34 // see http://src.opensolaris.org/source/xref/sfw/usr/src/cmd/gcc/gcc-3.4.3/gcc/testsuite/g++.old-deja/g++.abi/align.C
35 // Origin: Alex Samuel <samuel (at) codesourcery.com>
36 #define alignmentof(type) (std::alignment_of<type>())
37 // template<typename T>
38 // inline size_t alignment_of() {
39 // struct S {
40 // char c;
41 // T t;
42 // };
43 // return offsetof(S, t);
44 // }
45 
46 inline void test_alignment(void const* ptr, int align) {
47  union {
48  void const* p;
49  size_t i;
50  } u;
51  u.p = ptr;
52 
53  (void)u;
54  (void)align;
55 
56  // make sure the requested alignment is a power of 2
57  assert((align & -align) == align);
58 
59  // make sure the pointer is properly aligned
60  assert(((align - 1) & u.i) == 0);
61 }
62 
63 template<class T>
64 inline T* aligned_cast(void const* ptr) {
65  union {
66  void const* p;
67  T* t;
68  size_t i;
69  } u;
70  u.p = ptr;
71 
72  // make sure the pointer is properly aligned
73  assert(((alignmentof(T) - 1) & u.i) == 0);
74  return u.t;
75 }
76 
93 template<typename T>
94 class guard {
95 private:
96  T* _ptr;
97 
98 private:
99  // Specialize this function as necessary
100 
101  void action(T* ptr) {
102  if (ptr) {
103  delete ptr;
104  }
105  }
106 
107 
108  /* possible change
109  void action(T* ptr) {
110  if (ptr != nullptr)
111  delete ptr;
112  }
113  */
114 
115 public:
116 
117  guard(T* ptr = nullptr)
118  : _ptr(ptr) {}
119 
120  guard(guard& other)
121  : _ptr(other.release()) {}
122 
123  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
124  * WARNING:
125  *
126  * The copy constructor must be declared public in order for
127  * initializations of the form "guard<foo> f = ..." to compile
128  * (even though the function never actually gets called).
129  *
130  * That said, this function's body cannot be safely defined
131  * because there is no way for a const guard to release() its
132  * pointer. By declaring -- but not defining -- the copy
133  * constructor and its matching assignment operator we prevent
134  * multiple guards from accidentally fighting over the same
135  * pointer. The only remaining case is where the user
136  * independently creates two guards for the same pointer (not much
137  * we can do about that).
138  */
139  guard(guard const&);
140 
141  guard& operator=(const guard&);
142 
143  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
144 
145  guard& operator=(guard& other) {
146  assign(other.release());
147  return *this;
148  }
149 
150  guard& operator=(T* ptr) {
151  assign(ptr);
152  return *this;
153  }
154 
155  operator T*() {
156  return get();
157  }
158 
159  operator T const*() const {
160  return get();
161  }
162 
164  return *get();
165  }
166 
167  T const& operator*() const {
168  return *get();
169  }
170 
172  return get();
173  }
174 
175  T const* operator->() const {
176  return get();
177  }
178 
179  T* get() {
180  return _ptr;
181  }
182 
183  T const* get() const {
184  return _ptr;
185  }
186 
195  T* release() {
196  T* ptr = _ptr;
197  _ptr = nullptr;
198  return ptr;
199  }
200 
205  void done() {
206  assign(nullptr);
207  }
208 
209  ~guard() {
210  done();
211  }
212 
213 private:
214  void assign(T* ptr) {
215  if (_ptr && _ptr != ptr) {
216  action(_ptr);
217  }
218  _ptr = ptr;
219  }
220 };
221 
222 template<>
223 inline void guard<FILE>::action(FILE* ptr) {
224  if (fclose(ptr))
225  TRACE(TRACE_ALWAYS, "fclose failed");
226 }
227 
249 template<class T, class Impl>
251 protected:
252  mutable T _obj;
253 
254 public:
256 
257  // The value that represents "null" for typename T. Impl usually
258  // descends from this class so this makes a handy default
259  // implementation
260  static T null_value() {
261  return nullptr;
262  }
263 
264  static bool different(const T& a, const T& b) {
265  return a != b;
266  }
267 
269  : _obj(obj) {}
270 
272  : _obj(other.release()) {}
273 
275  assign(other.release());
276  return *this;
277  }
278 
279  operator T() const {
280  return get();
281  }
282 
283  T get() const {
284  return _obj;
285  }
286 
295  T release() const {
296  T obj = _obj;
297  _obj = Impl::null_value();
298  return obj;
299  }
300 
305  void done() const {
306  assign(Impl::null_value());
307  }
308 
310  done();
311  }
312 
313 protected:
314  void assign(T obj) const {
315  if (Impl::different(_obj, obj)) {
316  // free the old object and set it NULL
317  Impl::guard_action(_obj);
318  _obj = obj;
319  }
320  }
321 };
322 
323 template<typename T, typename Impl>
324 struct pointer_guard_base_t : guard_base_t<T*, Impl> {
326 
328  : Base(ptr) {}
329 
330  T& operator*() const {
331  return *Base::get();
332  }
333 
334  operator T*() const {
335  return Base::get();
336  }
337 
338  T* operator->() const {
339  return Base::get();
340  }
341 };
342 
347 template<class T>
348 struct pointer_guard_t : pointer_guard_base_t<T, pointer_guard_t<T>> {
349  pointer_guard_t(T* ptr = nullptr)
351 
352  static void guard_action(T* ptr) {
353  delete ptr;
354  }
355 };
356 
361 template<class T>
362 struct array_guard_t : pointer_guard_base_t<T, array_guard_t<T>> {
363  array_guard_t(T* ptr = nullptr)
365 
366  static void guard_action(T* ptr) {
367  delete[] ptr;
368  }
369 };
370 
374 struct file_guard_t : pointer_guard_base_t<FILE, file_guard_t> {
375  file_guard_t(FILE* ptr = nullptr)
376  : pointer_guard_base_t<FILE, file_guard_t>(ptr) {}
377 
378  static void guard_action(FILE* ptr) {
379  if (ptr && fclose(ptr)) {
381  "fclose failed in guard destructor");
382  }
383  }
384 };
385 
389 struct fd_guard_t : guard_base_t<int, fd_guard_t> {
390  fd_guard_t(int fd)
391  : guard_base_t<int, fd_guard_t>(fd) {}
392 
393  static void guard_action(int fd) {
394  if (fd >= 0 && close(fd))
395  TRACE(TRACE_ALWAYS, "close() failed in guard destructor");
396  }
397 
398  static int null_value() {
399  return -1;
400  }
401 };
402 
403 #endif // __GUARD_H
void test_alignment(void const *ptr, int align)
Definition: guard.h:46
T * release()
Notifies this guard that its services are no longer needed because some other entity has assumed owne...
Definition: guard.h:195
Tracing module.
pointer_guard_base_t(T *ptr)
Definition: guard.h:327
T const * operator->() const
Definition: guard.h:175
Definition: guard.h:324
T & operator*()
Definition: guard.h:163
guard(T *ptr=nullptr)
Definition: guard.h:117
void assign(T *ptr)
Definition: guard.h:214
static void guard_action(T *ptr)
Definition: guard.h:366
T * aligned_cast(void const *ptr)
Definition: guard.h:64
void assign(T obj) const
Definition: guard.h:314
void done()
Notifies this guard that its action should be performed now rather than at destruct time...
Definition: guard.h:205
void action(T *ptr)
Definition: guard.h:101
~guard()
Definition: guard.h:209
guard & operator=(guard &other)
Definition: guard.h:145
static int null_value()
Definition: guard.h:398
A generic pointer guard base class. An action will be performed exactly once on the stored pointer...
Definition: guard.h:250
static T null_value()
Definition: guard.h:260
guard_base_t< T, Impl > Base
Definition: guard.h:255
static void guard_action(FILE *ptr)
Definition: guard.h:378
static void guard_action(T *ptr)
Definition: guard.h:352
Ensures that a file descriptor gets closed.
Definition: guard.h:389
file_guard_t(FILE *ptr=nullptr)
Definition: guard.h:375
guard & operator=(const guard &)
Ensures that an array allocated with a call to operator new() gets deleted.
Definition: guard.h:362
fd_guard_t(int fd)
Definition: guard.h:390
#define alignmentof(type)
Definition: guard.h:36
void done() const
Notifies this guard that its action should be performed now rather than at destruct time...
Definition: guard.h:305
T * _ptr
Definition: guard.h:96
Ensures that a file gets closed.
Definition: guard.h:374
guard_base_t & operator=(const guard_base_t &other)
Definition: guard.h:274
guard_base_t(T obj)
Definition: guard.h:268
guard_base_t< T *, Impl > Base
Definition: guard.h:325
T * operator->()
Definition: guard.h:171
pointer_guard_t(T *ptr=nullptr)
Definition: guard.h:349
static bool different(const T &a, const T &b)
Definition: guard.h:264
#define TRACE
Other modules in our program use this macro for reporting. We can use preprocessor macros like FILE a...
Definition: trace.h:91
static void guard_action(int fd)
Definition: guard.h:393
T * operator->() const
Definition: guard.h:338
array_guard_t(T *ptr=nullptr)
Definition: guard.h:363
T release() const
Notifies this guard that its services are no longer needed because some other entity has assumed owne...
Definition: guard.h:295
T const & operator*() const
Definition: guard.h:167
guard(guard &other)
Definition: guard.h:120
~guard_base_t()
Definition: guard.h:309
#define TRACE_ALWAYS
Definition: trace_types.h:41
T & operator*() const
Definition: guard.h:330
guard & operator=(T *ptr)
Definition: guard.h:150
A generic RAII guard class.
Definition: guard.h:94
guard_base_t(const guard_base_t &other)
Definition: guard.h:271
#define T
Definition: w_okvl_inl.h:45
Ensures that a pointer allocated with a call to operator new() gets deleted.
Definition: guard.h:348
T _obj
Definition: guard.h:252