summaryrefslogtreecommitdiff
path: root/klm/util/scoped.hh
blob: 60c36c36a95a41e821ecbbbfc37aa77c5aa795fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#ifndef UTIL_SCOPED_H
#define UTIL_SCOPED_H
/* Other scoped objects in the style of scoped_ptr. */

#include "util/exception.hh"
#include <cstddef>
#include <cstdlib>

namespace util {

class MallocException : public ErrnoException {
  public:
    explicit MallocException(std::size_t requested) throw();
    ~MallocException() throw();
};

void *MallocOrThrow(std::size_t requested);
void *CallocOrThrow(std::size_t requested);

/* Unfortunately, defining the operator* for void * makes the compiler complain.
 * So scoped is specialized to void.  This includes the functionality common to
 * both, namely everything except reference.
 */
template <class T, class Closer> class scoped_base {
  public:
    explicit scoped_base(T *p = NULL) : p_(p) {}

    ~scoped_base() { Closer::Close(p_); }

    void reset(T *p = NULL) {
      scoped_base other(p_);
      p_ = p;
    }

    T *get() { return p_; }
    const T *get() const { return p_; }

    T *operator->() { return p_; }
    const T *operator->() const { return p_; }

    T *release() {
      T *ret = p_;
      p_ = NULL;
      return ret;
    }

  protected:
    T *p_;

  private:
    scoped_base(const scoped_base &);
    scoped_base &operator=(const scoped_base &);
};

template <class T, class Closer> class scoped : public scoped_base<T, Closer> {
  public:
    explicit scoped(T *p = NULL) : scoped_base<T, Closer>(p) {}

    T &operator*() { return *scoped_base<T, Closer>::p_; }
    const T&operator*() const { return *scoped_base<T, Closer>::p_; }
};

template <class Closer> class scoped<void, Closer> : public scoped_base<void, Closer> {
  public:
    explicit scoped(void *p = NULL) : scoped_base<void, Closer>(p) {}
};

/* Closer for c functions like std::free and cmph cleanup functions */
template <class T, void (*clean)(T*)> struct scoped_c_forward {
  static void Close(T *p) { clean(p); }
};
// Call a C function to delete stuff
template <class T, void (*clean)(T*)> class scoped_c : public scoped<T, scoped_c_forward<T, clean> > {
  public:
    explicit scoped_c(T *p = NULL) : scoped<T, scoped_c_forward<T, clean> >(p) {}
};

class scoped_malloc : public scoped_c<void, std::free> {
  public:
    explicit scoped_malloc(void *p = NULL) : scoped_c<void, std::free>(p) {}

    void call_realloc(std::size_t to);
};

/* scoped_array using delete[] */
struct scoped_delete_array_forward {
  template <class T> static void Close(T *p) { delete [] p; }
};
// Hat tip to boost.  
template <class T> class scoped_array : public scoped<T, scoped_delete_array_forward> {
  public:
    explicit scoped_array(T *p = NULL) : scoped<T, scoped_delete_array_forward>(p) {}

    T &operator[](std::size_t idx) { return scoped<T, scoped_delete_array_forward>::p_[idx]; }
    const T &operator[](std::size_t idx) const { return scoped<T, scoped_delete_array_forward>::p_[idx]; }
};

/* scoped_ptr using delete.  If only there were a template typedef. */
struct scoped_delete_forward {
  template <class T> static void Close(T *p) { delete p; }
};
template <class T> class scoped_ptr : public scoped<T, scoped_delete_forward> {
  public:
    explicit scoped_ptr(T *p = NULL) : scoped<T, scoped_delete_forward>(p) {}
};

} // namespace util

#endif // UTIL_SCOPED_H