1/* -----------------------------------------------------------------------------
2 * See the LICENSE file for information on copyright, usage and redistribution
3 * of SWIG, and the README file for authors - http://www.swig.org/release.html.
4 *
5 * director.swg
6 *
7 * This file contains support for director classes that proxy
8 * method calls from C++ to Ruby extensions.
9 * ----------------------------------------------------------------------------- */
10
11/*
12  Use -DSWIG_DIRECTOR_NOUEH if you prefer to avoid the use of the
13  Undefined Exception Handler provided by swift
14*/
15#ifndef SWIG_DIRECTOR_NOUEH
16#ifndef SWIG_DIRECTOR_UEH
17#define SWIG_DIRECTOR_UEH
18#endif
19#endif
20
21#ifdef __cplusplus
22
23#include <string>
24#include <iostream>
25#include <map>
26
27namespace Swig {
28  /* memory handler */
29  struct GCItem
30  {
31    virtual ~GCItem()
32    {
33    }
34
35    virtual ruby_owntype get_own() const
36    {
37      return 0;
38    }
39  };
40
41  struct GCItem_var
42  {
43    GCItem_var(GCItem *item = 0) : _item(item)
44    {
45    }
46
47    GCItem_var& operator=(GCItem *item)
48    {
49      GCItem *tmp = _item;
50      _item = item;
51      delete tmp;
52      return *this;
53    }
54
55    ~GCItem_var()
56    {
57      delete _item;
58    }
59
60    GCItem * operator->() const
61    {
62      return _item;
63    }
64
65  private:
66    GCItem *_item;
67  };
68
69
70  template <typename Type>
71  struct GCItem_T : GCItem
72  {
73    GCItem_T(Type *ptr) : _ptr(ptr)
74    {
75    }
76
77    virtual ~GCItem_T()
78    {
79      delete _ptr;
80    }
81
82  private:
83    Type *_ptr;
84  };
85
86  struct GCItem_Object : GCItem
87  {
88    GCItem_Object(ruby_owntype own) : _own(own)
89    {
90    }
91
92    virtual ~GCItem_Object()
93    {
94    }
95
96    ruby_owntype get_own() const
97    {
98      return _own;
99    }
100
101  private:
102    ruby_owntype _own;
103  };
104
105
106  template <typename Type>
107  struct GCArray_T : GCItem
108  {
109    GCArray_T(Type *ptr) : _ptr(ptr)
110    {
111    }
112
113    virtual ~GCArray_T()
114    {
115      delete[] _ptr;
116    }
117
118  private:
119    Type *_ptr;
120  };
121
122
123  /* body args */
124  struct body_args {
125    VALUE recv;
126    ID id;
127    int argc;
128    VALUE *argv;
129  };
130
131  /* Base class for director exceptions */
132  class DirectorException {
133  protected:
134    VALUE swig_error;
135    std::string swig_msg;
136  protected:
137    DirectorException(VALUE error)
138      : swig_error(error)
139    {
140    }
141
142    DirectorException(VALUE error, const char* hdr, const char* msg ="")
143      : swig_error(error), swig_msg(hdr) {
144      if (strlen(msg)) {
145	swig_msg += " ";
146	swig_msg += msg;
147      }
148      if (swig_msg.size()) {
149	VALUE str = rb_str_new(swig_msg.data(), swig_msg.size());
150	swig_error = rb_exc_new3(error, str);
151      } else {
152	swig_error = error;
153      }
154    }
155  public:
156    VALUE getType() const  {
157      return CLASS_OF(swig_error);
158    }
159    VALUE getError() const {
160      return swig_error;
161    }
162    const std::string& getMessage() const
163    {
164      return swig_msg;
165    }
166
167    virtual ~DirectorException() {}
168  };
169
170  /* unknown exception handler  */
171
172  class UnknownExceptionHandler
173  {
174#ifdef SWIG_DIRECTOR_UEH
175    static void handler() {
176      try {
177	throw;
178      } catch (DirectorException& e) {
179	std::cerr << "Swig Director exception caught:" << std::endl
180		  << e.getMessage() << std::endl;
181      } catch (std::exception& e) {
182	std::cerr << "std::exception caught: "<< e.what() << std::endl;
183      } catch (...) {
184	std::cerr << "Unknown exception caught." << std::endl;
185      }
186      std::cerr << std::endl
187		<< "Ruby interpreter traceback:" << std::endl;
188      std::cerr << std::endl;
189      std::cerr << "This exception was caught by the SWIG unexpected exception handler." << std::endl
190		<< "Try using %feature(\"director:except\") to avoid reaching this point." << std::endl
191		<< std::endl
192		<< "Exception is being re-thrown, program will like abort/terminate." << std::endl;
193      throw;
194    }
195
196  public:
197    std::unexpected_handler old;
198    UnknownExceptionHandler(std::unexpected_handler nh = handler)
199    {
200      old = std::set_unexpected(nh);
201    }
202
203    ~UnknownExceptionHandler()
204    {
205      std::set_unexpected(old);
206    }
207#endif
208  };
209
210
211  /* Type mismatch in the return value from a Ruby method call */
212  class DirectorTypeMismatchException : public Swig::DirectorException {
213  public:
214    DirectorTypeMismatchException(VALUE error, const char *msg="")
215      : Swig::DirectorException(error, "Swig director type mismatch", msg)
216    {
217    }
218
219    DirectorTypeMismatchException(const char *msg="")
220      : Swig::DirectorException(rb_eTypeError, "Swig director type mismatch", msg)
221    {
222    }
223
224    static void raise(VALUE error, const char *msg) {
225      throw DirectorTypeMismatchException(error, msg);
226    }
227
228    static void raise(const char *msg) {
229      throw DirectorTypeMismatchException(msg);
230    }
231  };
232
233  /* Any Ruby exception that occurs during a director method call */
234  class DirectorMethodException : public Swig::DirectorException {
235  public:
236    DirectorMethodException(VALUE error)
237      : Swig::DirectorException(error) {
238    }
239
240    DirectorMethodException(const char* msg = "")
241      : Swig::DirectorException(rb_eRuntimeError, "Swig director method error.", msg) {
242    }
243
244    static void raise(VALUE error)
245    {
246      throw DirectorMethodException(error);
247    }
248  };
249
250  /* Attempted to call a pure virtual method via a director method */
251  class DirectorPureVirtualException : public Swig::DirectorException
252  {
253  public:
254    DirectorPureVirtualException(const char* msg = "")
255      : DirectorException(rb_eRuntimeError, "Swig director pure virtual method called", msg)
256    {
257    }
258
259    static void raise(const char *msg)
260    {
261      throw DirectorPureVirtualException(msg);
262    }
263  };
264
265  /* Simple thread abstraction for pthreads on win32 */
266#ifdef __THREAD__
267# define __PTHREAD__
268# if defined(_WIN32) || defined(__WIN32__)
269#  define pthread_mutex_lock EnterCriticalSection
270#  define pthread_mutex_unlock LeaveCriticalSection
271#  define pthread_mutex_t CRITICAL_SECTION
272#  define SWIG_MUTEX_INIT(var) var
273# else
274#  include <pthread.h>
275#  define SWIG_MUTEX_INIT(var) var = PTHREAD_MUTEX_INITIALIZER
276# endif
277#endif
278
279#ifdef  __PTHREAD__
280  struct Guard
281  {
282    pthread_mutex_t *_mutex;
283
284    Guard(pthread_mutex_t &mutex) : _mutex(&mutex)
285    {
286      pthread_mutex_lock(_mutex);
287    }
288
289    ~Guard()
290    {
291      pthread_mutex_unlock(_mutex);
292    }
293  };
294# define SWIG_GUARD(mutex) Guard _guard(mutex)
295#else
296# define SWIG_GUARD(mutex)
297#endif
298
299  /* director base class */
300  class Director {
301  private:
302    /* pointer to the wrapped Ruby object */
303    VALUE swig_self;
304    /* flag indicating whether the object is owned by Ruby or c++ */
305    mutable bool swig_disown_flag;
306
307  public:
308    /* wrap a Ruby object, optionally taking ownership */
309    Director(VALUE self) : swig_self(self), swig_disown_flag(false) {
310    }
311
312    /* discard our reference at destruction */
313    virtual ~Director() {
314    }
315
316    /* return a pointer to the wrapped Ruby object */
317    VALUE swig_get_self() const {
318      return swig_self;
319    }
320
321    /* acquire ownership of the wrapped Ruby object (the sense of "disown"
322     * is from Ruby) */
323    void swig_disown() const {
324      if (!swig_disown_flag) {
325        swig_disown_flag = true;
326      }
327    }
328
329  /* ownership management */
330  private:
331    typedef std::map<void*, GCItem_var> ownership_map;
332    mutable ownership_map owner;
333#ifdef __PTHREAD__
334    static pthread_mutex_t swig_mutex_own;
335#endif
336
337  public:
338    template <typename Type>
339    void swig_acquire_ownership_array(Type *vptr)  const
340    {
341      if (vptr) {
342	SWIG_GUARD(swig_mutex_own);
343	owner[vptr] = new GCArray_T<Type>(vptr);
344      }
345    }
346
347    template <typename Type>
348    void swig_acquire_ownership(Type *vptr)  const
349    {
350      if (vptr) {
351	SWIG_GUARD(swig_mutex_own);
352	owner[vptr] = new GCItem_T<Type>(vptr);
353      }
354    }
355
356    void swig_acquire_ownership_obj(void *vptr, ruby_owntype own) const
357    {
358      if (vptr && own) {
359	SWIG_GUARD(swig_mutex_own);
360	owner[vptr] = new GCItem_Object(own);
361      }
362    }
363
364    ruby_owntype swig_release_ownership(void *vptr) const
365    {
366      ruby_owntype own = 0;
367      if (vptr) {
368	SWIG_GUARD(swig_mutex_own);
369	ownership_map::iterator iter = owner.find(vptr);
370	if (iter != owner.end()) {
371	  own = iter->second->get_own();
372	  owner.erase(iter);
373	}
374      }
375      return own;
376    }
377  };
378}
379
380#endif /* __cplusplus */
381
382
383